@mastra/editor 0.13.1-alpha.0 → 0.13.1-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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @mastra/editor
2
2
 
3
+ ## 0.13.1-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix editor.agent.update() to persist editable agent fields by creating and activating a new version. ([#18096](https://github.com/mastra-ai/mastra/pull/18096))
8
+
9
+ - Fixed prompt block SDK updates to persist editable fields. ([#17088](https://github.com/mastra-ai/mastra/pull/17088))
10
+
11
+ - Updated dependencies [[`65f255a`](https://github.com/mastra-ai/mastra/commit/65f255a38667beb6ceeadabfa9eb5059bfec8298), [`4a88c6e`](https://github.com/mastra-ai/mastra/commit/4a88c6e2bdce316f8d7551b4ec3449b0b06fc71c), [`87a17ef`](https://github.com/mastra-ai/mastra/commit/87a17efbd725aca6639febdc5e69e2abb3048689), [`e11ff30`](https://github.com/mastra-ai/mastra/commit/e11ff301408bf1731dca2fb7fbfcd8c819500a35), [`9d2c946`](https://github.com/mastra-ai/mastra/commit/9d2c946d0859e90ae4bcec5beeb1da7398d2ad1e), [`f1ec385`](https://github.com/mastra-ai/mastra/commit/f1ec385386f62b1a0847ec5353ae2bb169d1c3d9), [`e14986f`](https://github.com/mastra-ai/mastra/commit/e14986f6e5478d6384d04ff9a7f9a79a46a8b529), [`0be490f`](https://github.com/mastra-ai/mastra/commit/0be490fabb538c5a7de796ea0aff7d04a0bea1f3), [`0be490f`](https://github.com/mastra-ai/mastra/commit/0be490fabb538c5a7de796ea0aff7d04a0bea1f3), [`974f614`](https://github.com/mastra-ai/mastra/commit/974f614e083bd68278536f94453f7b320b86a3c7), [`cff28df`](https://github.com/mastra-ai/mastra/commit/cff28df33476e41c9538cf9dba7fc8013d69ebb1), [`31be1cf`](https://github.com/mastra-ai/mastra/commit/31be1cf5f2a7b5eef12f6123a40653b4d8115c16)]:
12
+ - @mastra/core@1.46.0-alpha.3
13
+ - @mastra/memory@1.21.1-alpha.1
14
+
3
15
  ## 0.13.1-alpha.0
4
16
 
5
17
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -871,7 +871,106 @@ var EditorMCPNamespace = class _EditorMCPNamespace extends CrudEditorNamespace {
871
871
  }
872
872
  };
873
873
 
874
+ // src/namespaces/versioned-update.ts
875
+ var import_utils = require("@mastra/core/utils");
876
+ function getProvidedSnapshotFields(input, snapshotFields) {
877
+ const config = {};
878
+ for (const field of snapshotFields) {
879
+ if (input[field] !== void 0) {
880
+ config[field] = input[field];
881
+ }
882
+ }
883
+ return config;
884
+ }
885
+ function extractSnapshotConfig(version, snapshotFields) {
886
+ const record = version;
887
+ const config = {};
888
+ for (const field of snapshotFields) {
889
+ if (field in record) {
890
+ config[field] = record[field];
891
+ }
892
+ }
893
+ return config;
894
+ }
895
+ function getChangedSnapshotFields(previousConfig, providedConfig, snapshotFields) {
896
+ return snapshotFields.filter(
897
+ (field) => field in providedConfig && !(0, import_utils.deepEqual)(previousConfig[field], providedConfig[field])
898
+ );
899
+ }
900
+ function isVersionNumberConflictError(error) {
901
+ if (!(error instanceof Error)) return false;
902
+ const message = error.message.toLowerCase();
903
+ return message.includes("unique") && message.includes("constraint") || message.includes("duplicate key") || message.includes("unique_violation") || message.includes("sqlite_constraint_unique") || message.includes("version number") && message.includes("already exists") || message.includes("versionnumber");
904
+ }
905
+ async function createVersionFromSnapshotUpdate({
906
+ store,
907
+ parentId,
908
+ parentIdField,
909
+ snapshotFields,
910
+ providedConfig,
911
+ changeMessage = "Auto-saved after edit",
912
+ maxRetries = 3
913
+ }) {
914
+ let lastError;
915
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
916
+ try {
917
+ const latestVersion = await store.getLatestVersion(parentId);
918
+ if (!latestVersion) {
919
+ return { versionCreated: false };
920
+ }
921
+ const previousConfig = extractSnapshotConfig(latestVersion, snapshotFields);
922
+ const changedFields = getChangedSnapshotFields(previousConfig, providedConfig, snapshotFields);
923
+ if (changedFields.length === 0) {
924
+ return { versionCreated: false };
925
+ }
926
+ const nextConfig = { ...previousConfig };
927
+ for (const [field, value] of Object.entries(providedConfig)) {
928
+ nextConfig[field] = value === null ? void 0 : value;
929
+ }
930
+ const version = await store.createVersion({
931
+ ...nextConfig,
932
+ id: crypto.randomUUID(),
933
+ [parentIdField]: parentId,
934
+ versionNumber: latestVersion.versionNumber + 1,
935
+ changedFields,
936
+ changeMessage
937
+ });
938
+ return { versionCreated: true, version, changedFields };
939
+ } catch (error) {
940
+ lastError = error;
941
+ if (isVersionNumberConflictError(error) && attempt < maxRetries - 1) {
942
+ await new Promise((resolve) => setTimeout(resolve, 10 * (attempt + 1)));
943
+ continue;
944
+ }
945
+ throw error;
946
+ }
947
+ }
948
+ throw lastError;
949
+ }
950
+
874
951
  // src/namespaces/agent.ts
952
+ var AGENT_SNAPSHOT_CONFIG_FIELDS = [
953
+ "name",
954
+ "description",
955
+ "instructions",
956
+ "model",
957
+ "tools",
958
+ "defaultOptions",
959
+ "workflows",
960
+ "agents",
961
+ "integrationTools",
962
+ "toolProviders",
963
+ "inputProcessors",
964
+ "outputProcessors",
965
+ "memory",
966
+ "scorers",
967
+ "requestContextSchema",
968
+ "mcpClients",
969
+ "skills",
970
+ "skillsFormat",
971
+ "workspace",
972
+ "browser"
973
+ ];
875
974
  var BUILDER_DEFAULT_FIELDS = ["memory", "workspace", "browser"];
876
975
  function defaultModelToStored(entry) {
877
976
  return { provider: entry.provider, name: entry.modelId };
@@ -902,6 +1001,16 @@ function applyBuilderDefaults(input, builderAgentConfig) {
902
1001
  }
903
1002
  return Object.keys(defaults).length > 0 ? { ...input, ...defaults } : input;
904
1003
  }
1004
+ function getProvidedAgentRecordFields(input) {
1005
+ const { id, authorId, visibility, activeVersionId, metadata, status } = input;
1006
+ const recordFields = { id };
1007
+ if (authorId !== void 0) recordFields.authorId = authorId;
1008
+ if (visibility !== void 0) recordFields.visibility = visibility;
1009
+ if (activeVersionId !== void 0) recordFields.activeVersionId = activeVersionId;
1010
+ if (metadata !== void 0) recordFields.metadata = metadata;
1011
+ if (status !== void 0) recordFields.status = status;
1012
+ return Object.keys(recordFields).length > 1 ? recordFields : null;
1013
+ }
905
1014
  var EditorAgentNamespace = class extends CrudEditorNamespace {
906
1015
  async getStorageAdapter() {
907
1016
  const storage = this.mastra?.getStorage();
@@ -944,6 +1053,53 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
944
1053
  async hydrate(storedAgent) {
945
1054
  return this.createAgentFromStoredConfig(storedAgent);
946
1055
  }
1056
+ async update(input) {
1057
+ this.ensureRegistered();
1058
+ const storage = this.mastra?.getStorage();
1059
+ if (!storage) throw new Error("Storage is not configured");
1060
+ const store = await storage.getStore("agents");
1061
+ if (!store) throw new Error("Agents storage domain is not available");
1062
+ const existing = await store.getById(input.id);
1063
+ if (!existing) {
1064
+ throw new Error(`Agent with id ${input.id} not found`);
1065
+ }
1066
+ const providedConfig = getProvidedSnapshotFields(
1067
+ input,
1068
+ AGENT_SNAPSHOT_CONFIG_FIELDS
1069
+ );
1070
+ if ("workspace" in providedConfig) {
1071
+ await this.ensureStoredWorkspaceRefs(providedConfig.workspace);
1072
+ }
1073
+ const versionResult = Object.keys(providedConfig).length > 0 ? await createVersionFromSnapshotUpdate({
1074
+ store,
1075
+ parentId: input.id,
1076
+ parentIdField: "agentId",
1077
+ snapshotFields: AGENT_SNAPSHOT_CONFIG_FIELDS,
1078
+ providedConfig
1079
+ }) : { versionCreated: false };
1080
+ const recordFields = getProvidedAgentRecordFields(input);
1081
+ if (recordFields || versionResult.versionCreated) {
1082
+ await store.update({
1083
+ ...recordFields ?? { id: input.id },
1084
+ ...versionResult.versionCreated ? { activeVersionId: versionResult.version.id } : {}
1085
+ });
1086
+ }
1087
+ this._cache.delete(input.id);
1088
+ this.onCacheEvict(input.id);
1089
+ const existingCodeAgent = this.getCodeDefinedAgent(input.id);
1090
+ if (existingCodeAgent) {
1091
+ const hydrated2 = await this.applyStoredOverrides(existingCodeAgent, { status: "draft" });
1092
+ this._cache.set(input.id, hydrated2);
1093
+ return hydrated2;
1094
+ }
1095
+ const resolved = await store.getByIdResolved(input.id, { status: "draft" });
1096
+ if (!resolved) {
1097
+ throw new Error(`Failed to resolve entity ${input.id} after update`);
1098
+ }
1099
+ const hydrated = await this.hydrate(resolved);
1100
+ this._cache.set(input.id, hydrated);
1101
+ return hydrated;
1102
+ }
947
1103
  /**
948
1104
  * Create a new agent, applying builder defaults for fields not specified in input.
949
1105
  * Also ensures the referenced workspace (if any) is persisted as a stored workspace.
@@ -974,6 +1130,16 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
974
1130
  }
975
1131
  return agent?.source === "code" ? agent : void 0;
976
1132
  }
1133
+ async ensureStoredWorkspaceRefs(workspace2) {
1134
+ if (!workspace2) return;
1135
+ if (this.isConditionalVariants(workspace2)) {
1136
+ for (const variant of workspace2) {
1137
+ await this.ensureStoredWorkspace(variant.value);
1138
+ }
1139
+ return;
1140
+ }
1141
+ await this.ensureStoredWorkspace(workspace2);
1142
+ }
977
1143
  /**
978
1144
  * Ensure a workspace reference is persisted in the DB.
979
1145
  *
@@ -2117,6 +2283,96 @@ var EditorMCPServerNamespace = class extends CrudEditorNamespace {
2117
2283
  };
2118
2284
 
2119
2285
  // src/namespaces/prompt.ts
2286
+ var PROMPT_BLOCK_SNAPSHOT_CONFIG_FIELDS = [
2287
+ "name",
2288
+ "description",
2289
+ "content",
2290
+ "rules",
2291
+ "requestContextSchema"
2292
+ ];
2293
+ function deepEqual2(a, b) {
2294
+ if (a === b) return true;
2295
+ if (a == null || b == null) return a === b;
2296
+ if (typeof a !== typeof b) return false;
2297
+ if (Array.isArray(a) && Array.isArray(b)) {
2298
+ return a.length === b.length && a.every((item, index) => deepEqual2(item, b[index]));
2299
+ }
2300
+ if (typeof a === "object" && typeof b === "object") {
2301
+ const aObj = a;
2302
+ const bObj = b;
2303
+ const aKeys = Object.keys(aObj);
2304
+ const bKeys = Object.keys(bObj);
2305
+ return aKeys.length === bKeys.length && aKeys.every((key) => deepEqual2(aObj[key], bObj[key]));
2306
+ }
2307
+ return false;
2308
+ }
2309
+ function extractConfigFromVersion(version) {
2310
+ return {
2311
+ name: version.name,
2312
+ description: version.description,
2313
+ content: version.content,
2314
+ rules: version.rules,
2315
+ requestContextSchema: version.requestContextSchema
2316
+ };
2317
+ }
2318
+ function getProvidedConfigFields(input) {
2319
+ const config = {};
2320
+ for (const field of PROMPT_BLOCK_SNAPSHOT_CONFIG_FIELDS) {
2321
+ if (input[field] !== void 0) {
2322
+ config[field] = input[field];
2323
+ }
2324
+ }
2325
+ return config;
2326
+ }
2327
+ function getProvidedRecordFields(input) {
2328
+ const { id, authorId, activeVersionId, metadata, status } = input;
2329
+ const recordFields = { id };
2330
+ if (authorId !== void 0) recordFields.authorId = authorId;
2331
+ if (activeVersionId !== void 0) recordFields.activeVersionId = activeVersionId;
2332
+ if (metadata !== void 0) recordFields.metadata = metadata;
2333
+ if (status !== void 0) recordFields.status = status;
2334
+ return Object.keys(recordFields).length > 1 ? recordFields : null;
2335
+ }
2336
+ function getChangedFields(previousConfig, providedConfig) {
2337
+ return PROMPT_BLOCK_SNAPSHOT_CONFIG_FIELDS.filter(
2338
+ (field) => field in providedConfig && !deepEqual2(previousConfig[field], providedConfig[field])
2339
+ );
2340
+ }
2341
+ function isVersionNumberConflictError2(error) {
2342
+ if (!(error instanceof Error)) return false;
2343
+ const message = error.message.toLowerCase();
2344
+ return message.includes("unique") && message.includes("constraint") || message.includes("duplicate key") || message.includes("unique_violation") || message.includes("sqlite_constraint_unique") || message.includes("version number") && message.includes("already exists") || message.includes("versionnumber");
2345
+ }
2346
+ async function createPromptBlockVersionWithRetry(store, blockId, providedConfig, maxRetries = 3) {
2347
+ let lastError;
2348
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
2349
+ try {
2350
+ const latestVersion = await store.getLatestVersion(blockId);
2351
+ if (!latestVersion) return false;
2352
+ const previousConfig = extractConfigFromVersion(latestVersion);
2353
+ const changedFields = getChangedFields(previousConfig, providedConfig);
2354
+ if (changedFields.length === 0) return false;
2355
+ await store.createVersion({
2356
+ ...previousConfig,
2357
+ ...providedConfig,
2358
+ id: crypto.randomUUID(),
2359
+ blockId,
2360
+ versionNumber: latestVersion.versionNumber + 1,
2361
+ changedFields,
2362
+ changeMessage: "Auto-saved after edit"
2363
+ });
2364
+ return true;
2365
+ } catch (error) {
2366
+ lastError = error;
2367
+ if (isVersionNumberConflictError2(error) && attempt < maxRetries - 1) {
2368
+ await new Promise((resolve) => setTimeout(resolve, 10 * (attempt + 1)));
2369
+ continue;
2370
+ }
2371
+ throw error;
2372
+ }
2373
+ }
2374
+ throw lastError;
2375
+ }
2120
2376
  var EditorPromptNamespace = class extends CrudEditorNamespace {
2121
2377
  onCacheEvict(id) {
2122
2378
  this.mastra?.removePromptBlock(id);
@@ -2135,6 +2391,33 @@ var EditorPromptNamespace = class extends CrudEditorNamespace {
2135
2391
  listResolved: (args) => store.listResolved(args)
2136
2392
  };
2137
2393
  }
2394
+ async update(input) {
2395
+ this.ensureRegistered();
2396
+ const storage = this.mastra?.getStorage();
2397
+ if (!storage) throw new Error("Storage is not configured");
2398
+ const store = await storage.getStore("promptBlocks");
2399
+ if (!store) throw new Error("Prompt blocks storage domain is not available");
2400
+ const existing = await store.getById(input.id);
2401
+ if (!existing) {
2402
+ throw new Error(`Prompt block with id ${input.id} not found`);
2403
+ }
2404
+ const providedConfig = getProvidedConfigFields(input);
2405
+ if (Object.keys(providedConfig).length > 0) {
2406
+ await createPromptBlockVersionWithRetry(store, input.id, providedConfig);
2407
+ }
2408
+ const recordFields = getProvidedRecordFields(input);
2409
+ if (recordFields) {
2410
+ await store.update(recordFields);
2411
+ }
2412
+ this._cache.delete(input.id);
2413
+ this.onCacheEvict(input.id);
2414
+ const resolved = await store.getByIdResolved(input.id, { status: "draft" });
2415
+ if (!resolved) {
2416
+ throw new Error(`Failed to resolve entity ${input.id} after update`);
2417
+ }
2418
+ this._cache.set(input.id, resolved);
2419
+ return resolved;
2420
+ }
2138
2421
  async preview(blocks, context) {
2139
2422
  this.ensureRegistered();
2140
2423
  const storage = this.mastra?.getStorage();