@mastra/editor 0.13.1-alpha.0 → 0.13.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 +25 -0
- package/dist/index.cjs +283 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +283 -0
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.d.cts
CHANGED
|
@@ -96,12 +96,14 @@ declare class EditorAgentNamespace extends CrudEditorNamespace<StorageCreateAgen
|
|
|
96
96
|
* Hydrate a stored agent config into a runtime Agent instance.
|
|
97
97
|
*/
|
|
98
98
|
protected hydrate(storedAgent: StorageResolvedAgentType): Promise<Agent>;
|
|
99
|
+
update(input: StorageUpdateAgentInput): Promise<Agent>;
|
|
99
100
|
/**
|
|
100
101
|
* Create a new agent, applying builder defaults for fields not specified in input.
|
|
101
102
|
* Also ensures the referenced workspace (if any) is persisted as a stored workspace.
|
|
102
103
|
*/
|
|
103
104
|
create(input: StorageCreateAgentInput): Promise<Agent>;
|
|
104
105
|
private getCodeDefinedAgent;
|
|
106
|
+
private ensureStoredWorkspaceRefs;
|
|
105
107
|
/**
|
|
106
108
|
* Ensure a workspace reference is persisted in the DB.
|
|
107
109
|
*
|
|
@@ -267,6 +269,7 @@ declare class EditorMCPServerNamespace extends CrudEditorNamespace<StorageCreate
|
|
|
267
269
|
declare class EditorPromptNamespace extends CrudEditorNamespace<StorageCreatePromptBlockInput, StorageUpdatePromptBlockInput, StorageListPromptBlocksInput, StorageListPromptBlocksOutput, StorageListPromptBlocksResolvedOutput, StorageResolvedPromptBlockType> {
|
|
268
270
|
protected onCacheEvict(id: string): void;
|
|
269
271
|
protected getStorageAdapter(): Promise<StorageAdapter<StorageCreatePromptBlockInput, StorageUpdatePromptBlockInput, StorageListPromptBlocksInput, StorageListPromptBlocksOutput, StorageListPromptBlocksResolvedOutput, StorageResolvedPromptBlockType>>;
|
|
272
|
+
update(input: StorageUpdatePromptBlockInput): Promise<StorageResolvedPromptBlockType>;
|
|
270
273
|
preview(blocks: AgentInstructionBlock[], context: Record<string, unknown>): Promise<string>;
|
|
271
274
|
}
|
|
272
275
|
|
package/dist/index.d.ts
CHANGED
|
@@ -96,12 +96,14 @@ declare class EditorAgentNamespace extends CrudEditorNamespace<StorageCreateAgen
|
|
|
96
96
|
* Hydrate a stored agent config into a runtime Agent instance.
|
|
97
97
|
*/
|
|
98
98
|
protected hydrate(storedAgent: StorageResolvedAgentType): Promise<Agent>;
|
|
99
|
+
update(input: StorageUpdateAgentInput): Promise<Agent>;
|
|
99
100
|
/**
|
|
100
101
|
* Create a new agent, applying builder defaults for fields not specified in input.
|
|
101
102
|
* Also ensures the referenced workspace (if any) is persisted as a stored workspace.
|
|
102
103
|
*/
|
|
103
104
|
create(input: StorageCreateAgentInput): Promise<Agent>;
|
|
104
105
|
private getCodeDefinedAgent;
|
|
106
|
+
private ensureStoredWorkspaceRefs;
|
|
105
107
|
/**
|
|
106
108
|
* Ensure a workspace reference is persisted in the DB.
|
|
107
109
|
*
|
|
@@ -267,6 +269,7 @@ declare class EditorMCPServerNamespace extends CrudEditorNamespace<StorageCreate
|
|
|
267
269
|
declare class EditorPromptNamespace extends CrudEditorNamespace<StorageCreatePromptBlockInput, StorageUpdatePromptBlockInput, StorageListPromptBlocksInput, StorageListPromptBlocksOutput, StorageListPromptBlocksResolvedOutput, StorageResolvedPromptBlockType> {
|
|
268
270
|
protected onCacheEvict(id: string): void;
|
|
269
271
|
protected getStorageAdapter(): Promise<StorageAdapter<StorageCreatePromptBlockInput, StorageUpdatePromptBlockInput, StorageListPromptBlocksInput, StorageListPromptBlocksOutput, StorageListPromptBlocksResolvedOutput, StorageResolvedPromptBlockType>>;
|
|
272
|
+
update(input: StorageUpdatePromptBlockInput): Promise<StorageResolvedPromptBlockType>;
|
|
270
273
|
preview(blocks: AgentInstructionBlock[], context: Record<string, unknown>): Promise<string>;
|
|
271
274
|
}
|
|
272
275
|
|
package/dist/index.js
CHANGED
|
@@ -525,7 +525,106 @@ var EditorMCPNamespace = class _EditorMCPNamespace extends CrudEditorNamespace {
|
|
|
525
525
|
}
|
|
526
526
|
};
|
|
527
527
|
|
|
528
|
+
// src/namespaces/versioned-update.ts
|
|
529
|
+
import { deepEqual } from "@mastra/core/utils";
|
|
530
|
+
function getProvidedSnapshotFields(input, snapshotFields) {
|
|
531
|
+
const config = {};
|
|
532
|
+
for (const field of snapshotFields) {
|
|
533
|
+
if (input[field] !== void 0) {
|
|
534
|
+
config[field] = input[field];
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return config;
|
|
538
|
+
}
|
|
539
|
+
function extractSnapshotConfig(version, snapshotFields) {
|
|
540
|
+
const record = version;
|
|
541
|
+
const config = {};
|
|
542
|
+
for (const field of snapshotFields) {
|
|
543
|
+
if (field in record) {
|
|
544
|
+
config[field] = record[field];
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return config;
|
|
548
|
+
}
|
|
549
|
+
function getChangedSnapshotFields(previousConfig, providedConfig, snapshotFields) {
|
|
550
|
+
return snapshotFields.filter(
|
|
551
|
+
(field) => field in providedConfig && !deepEqual(previousConfig[field], providedConfig[field])
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
function isVersionNumberConflictError(error) {
|
|
555
|
+
if (!(error instanceof Error)) return false;
|
|
556
|
+
const message = error.message.toLowerCase();
|
|
557
|
+
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");
|
|
558
|
+
}
|
|
559
|
+
async function createVersionFromSnapshotUpdate({
|
|
560
|
+
store,
|
|
561
|
+
parentId,
|
|
562
|
+
parentIdField,
|
|
563
|
+
snapshotFields,
|
|
564
|
+
providedConfig,
|
|
565
|
+
changeMessage = "Auto-saved after edit",
|
|
566
|
+
maxRetries = 3
|
|
567
|
+
}) {
|
|
568
|
+
let lastError;
|
|
569
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
570
|
+
try {
|
|
571
|
+
const latestVersion = await store.getLatestVersion(parentId);
|
|
572
|
+
if (!latestVersion) {
|
|
573
|
+
return { versionCreated: false };
|
|
574
|
+
}
|
|
575
|
+
const previousConfig = extractSnapshotConfig(latestVersion, snapshotFields);
|
|
576
|
+
const changedFields = getChangedSnapshotFields(previousConfig, providedConfig, snapshotFields);
|
|
577
|
+
if (changedFields.length === 0) {
|
|
578
|
+
return { versionCreated: false };
|
|
579
|
+
}
|
|
580
|
+
const nextConfig = { ...previousConfig };
|
|
581
|
+
for (const [field, value] of Object.entries(providedConfig)) {
|
|
582
|
+
nextConfig[field] = value === null ? void 0 : value;
|
|
583
|
+
}
|
|
584
|
+
const version = await store.createVersion({
|
|
585
|
+
...nextConfig,
|
|
586
|
+
id: crypto.randomUUID(),
|
|
587
|
+
[parentIdField]: parentId,
|
|
588
|
+
versionNumber: latestVersion.versionNumber + 1,
|
|
589
|
+
changedFields,
|
|
590
|
+
changeMessage
|
|
591
|
+
});
|
|
592
|
+
return { versionCreated: true, version, changedFields };
|
|
593
|
+
} catch (error) {
|
|
594
|
+
lastError = error;
|
|
595
|
+
if (isVersionNumberConflictError(error) && attempt < maxRetries - 1) {
|
|
596
|
+
await new Promise((resolve) => setTimeout(resolve, 10 * (attempt + 1)));
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
throw error;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
throw lastError;
|
|
603
|
+
}
|
|
604
|
+
|
|
528
605
|
// src/namespaces/agent.ts
|
|
606
|
+
var AGENT_SNAPSHOT_CONFIG_FIELDS = [
|
|
607
|
+
"name",
|
|
608
|
+
"description",
|
|
609
|
+
"instructions",
|
|
610
|
+
"model",
|
|
611
|
+
"tools",
|
|
612
|
+
"defaultOptions",
|
|
613
|
+
"workflows",
|
|
614
|
+
"agents",
|
|
615
|
+
"integrationTools",
|
|
616
|
+
"toolProviders",
|
|
617
|
+
"inputProcessors",
|
|
618
|
+
"outputProcessors",
|
|
619
|
+
"memory",
|
|
620
|
+
"scorers",
|
|
621
|
+
"requestContextSchema",
|
|
622
|
+
"mcpClients",
|
|
623
|
+
"skills",
|
|
624
|
+
"skillsFormat",
|
|
625
|
+
"workspace",
|
|
626
|
+
"browser"
|
|
627
|
+
];
|
|
529
628
|
var BUILDER_DEFAULT_FIELDS = ["memory", "workspace", "browser"];
|
|
530
629
|
function defaultModelToStored(entry) {
|
|
531
630
|
return { provider: entry.provider, name: entry.modelId };
|
|
@@ -556,6 +655,16 @@ function applyBuilderDefaults(input, builderAgentConfig) {
|
|
|
556
655
|
}
|
|
557
656
|
return Object.keys(defaults).length > 0 ? { ...input, ...defaults } : input;
|
|
558
657
|
}
|
|
658
|
+
function getProvidedAgentRecordFields(input) {
|
|
659
|
+
const { id, authorId, visibility, activeVersionId, metadata, status } = input;
|
|
660
|
+
const recordFields = { id };
|
|
661
|
+
if (authorId !== void 0) recordFields.authorId = authorId;
|
|
662
|
+
if (visibility !== void 0) recordFields.visibility = visibility;
|
|
663
|
+
if (activeVersionId !== void 0) recordFields.activeVersionId = activeVersionId;
|
|
664
|
+
if (metadata !== void 0) recordFields.metadata = metadata;
|
|
665
|
+
if (status !== void 0) recordFields.status = status;
|
|
666
|
+
return Object.keys(recordFields).length > 1 ? recordFields : null;
|
|
667
|
+
}
|
|
559
668
|
var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
560
669
|
async getStorageAdapter() {
|
|
561
670
|
const storage = this.mastra?.getStorage();
|
|
@@ -598,6 +707,53 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
598
707
|
async hydrate(storedAgent) {
|
|
599
708
|
return this.createAgentFromStoredConfig(storedAgent);
|
|
600
709
|
}
|
|
710
|
+
async update(input) {
|
|
711
|
+
this.ensureRegistered();
|
|
712
|
+
const storage = this.mastra?.getStorage();
|
|
713
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
714
|
+
const store = await storage.getStore("agents");
|
|
715
|
+
if (!store) throw new Error("Agents storage domain is not available");
|
|
716
|
+
const existing = await store.getById(input.id);
|
|
717
|
+
if (!existing) {
|
|
718
|
+
throw new Error(`Agent with id ${input.id} not found`);
|
|
719
|
+
}
|
|
720
|
+
const providedConfig = getProvidedSnapshotFields(
|
|
721
|
+
input,
|
|
722
|
+
AGENT_SNAPSHOT_CONFIG_FIELDS
|
|
723
|
+
);
|
|
724
|
+
if ("workspace" in providedConfig) {
|
|
725
|
+
await this.ensureStoredWorkspaceRefs(providedConfig.workspace);
|
|
726
|
+
}
|
|
727
|
+
const versionResult = Object.keys(providedConfig).length > 0 ? await createVersionFromSnapshotUpdate({
|
|
728
|
+
store,
|
|
729
|
+
parentId: input.id,
|
|
730
|
+
parentIdField: "agentId",
|
|
731
|
+
snapshotFields: AGENT_SNAPSHOT_CONFIG_FIELDS,
|
|
732
|
+
providedConfig
|
|
733
|
+
}) : { versionCreated: false };
|
|
734
|
+
const recordFields = getProvidedAgentRecordFields(input);
|
|
735
|
+
if (recordFields || versionResult.versionCreated) {
|
|
736
|
+
await store.update({
|
|
737
|
+
...recordFields ?? { id: input.id },
|
|
738
|
+
...versionResult.versionCreated ? { activeVersionId: versionResult.version.id } : {}
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
this._cache.delete(input.id);
|
|
742
|
+
this.onCacheEvict(input.id);
|
|
743
|
+
const existingCodeAgent = this.getCodeDefinedAgent(input.id);
|
|
744
|
+
if (existingCodeAgent) {
|
|
745
|
+
const hydrated2 = await this.applyStoredOverrides(existingCodeAgent, { status: "draft" });
|
|
746
|
+
this._cache.set(input.id, hydrated2);
|
|
747
|
+
return hydrated2;
|
|
748
|
+
}
|
|
749
|
+
const resolved = await store.getByIdResolved(input.id, { status: "draft" });
|
|
750
|
+
if (!resolved) {
|
|
751
|
+
throw new Error(`Failed to resolve entity ${input.id} after update`);
|
|
752
|
+
}
|
|
753
|
+
const hydrated = await this.hydrate(resolved);
|
|
754
|
+
this._cache.set(input.id, hydrated);
|
|
755
|
+
return hydrated;
|
|
756
|
+
}
|
|
601
757
|
/**
|
|
602
758
|
* Create a new agent, applying builder defaults for fields not specified in input.
|
|
603
759
|
* Also ensures the referenced workspace (if any) is persisted as a stored workspace.
|
|
@@ -628,6 +784,16 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
628
784
|
}
|
|
629
785
|
return agent?.source === "code" ? agent : void 0;
|
|
630
786
|
}
|
|
787
|
+
async ensureStoredWorkspaceRefs(workspace) {
|
|
788
|
+
if (!workspace) return;
|
|
789
|
+
if (this.isConditionalVariants(workspace)) {
|
|
790
|
+
for (const variant of workspace) {
|
|
791
|
+
await this.ensureStoredWorkspace(variant.value);
|
|
792
|
+
}
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
await this.ensureStoredWorkspace(workspace);
|
|
796
|
+
}
|
|
631
797
|
/**
|
|
632
798
|
* Ensure a workspace reference is persisted in the DB.
|
|
633
799
|
*
|
|
@@ -1771,6 +1937,96 @@ var EditorMCPServerNamespace = class extends CrudEditorNamespace {
|
|
|
1771
1937
|
};
|
|
1772
1938
|
|
|
1773
1939
|
// src/namespaces/prompt.ts
|
|
1940
|
+
var PROMPT_BLOCK_SNAPSHOT_CONFIG_FIELDS = [
|
|
1941
|
+
"name",
|
|
1942
|
+
"description",
|
|
1943
|
+
"content",
|
|
1944
|
+
"rules",
|
|
1945
|
+
"requestContextSchema"
|
|
1946
|
+
];
|
|
1947
|
+
function deepEqual2(a, b) {
|
|
1948
|
+
if (a === b) return true;
|
|
1949
|
+
if (a == null || b == null) return a === b;
|
|
1950
|
+
if (typeof a !== typeof b) return false;
|
|
1951
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
1952
|
+
return a.length === b.length && a.every((item, index) => deepEqual2(item, b[index]));
|
|
1953
|
+
}
|
|
1954
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
1955
|
+
const aObj = a;
|
|
1956
|
+
const bObj = b;
|
|
1957
|
+
const aKeys = Object.keys(aObj);
|
|
1958
|
+
const bKeys = Object.keys(bObj);
|
|
1959
|
+
return aKeys.length === bKeys.length && aKeys.every((key) => deepEqual2(aObj[key], bObj[key]));
|
|
1960
|
+
}
|
|
1961
|
+
return false;
|
|
1962
|
+
}
|
|
1963
|
+
function extractConfigFromVersion(version) {
|
|
1964
|
+
return {
|
|
1965
|
+
name: version.name,
|
|
1966
|
+
description: version.description,
|
|
1967
|
+
content: version.content,
|
|
1968
|
+
rules: version.rules,
|
|
1969
|
+
requestContextSchema: version.requestContextSchema
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
function getProvidedConfigFields(input) {
|
|
1973
|
+
const config = {};
|
|
1974
|
+
for (const field of PROMPT_BLOCK_SNAPSHOT_CONFIG_FIELDS) {
|
|
1975
|
+
if (input[field] !== void 0) {
|
|
1976
|
+
config[field] = input[field];
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
return config;
|
|
1980
|
+
}
|
|
1981
|
+
function getProvidedRecordFields(input) {
|
|
1982
|
+
const { id, authorId, activeVersionId, metadata, status } = input;
|
|
1983
|
+
const recordFields = { id };
|
|
1984
|
+
if (authorId !== void 0) recordFields.authorId = authorId;
|
|
1985
|
+
if (activeVersionId !== void 0) recordFields.activeVersionId = activeVersionId;
|
|
1986
|
+
if (metadata !== void 0) recordFields.metadata = metadata;
|
|
1987
|
+
if (status !== void 0) recordFields.status = status;
|
|
1988
|
+
return Object.keys(recordFields).length > 1 ? recordFields : null;
|
|
1989
|
+
}
|
|
1990
|
+
function getChangedFields(previousConfig, providedConfig) {
|
|
1991
|
+
return PROMPT_BLOCK_SNAPSHOT_CONFIG_FIELDS.filter(
|
|
1992
|
+
(field) => field in providedConfig && !deepEqual2(previousConfig[field], providedConfig[field])
|
|
1993
|
+
);
|
|
1994
|
+
}
|
|
1995
|
+
function isVersionNumberConflictError2(error) {
|
|
1996
|
+
if (!(error instanceof Error)) return false;
|
|
1997
|
+
const message = error.message.toLowerCase();
|
|
1998
|
+
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");
|
|
1999
|
+
}
|
|
2000
|
+
async function createPromptBlockVersionWithRetry(store, blockId, providedConfig, maxRetries = 3) {
|
|
2001
|
+
let lastError;
|
|
2002
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
2003
|
+
try {
|
|
2004
|
+
const latestVersion = await store.getLatestVersion(blockId);
|
|
2005
|
+
if (!latestVersion) return false;
|
|
2006
|
+
const previousConfig = extractConfigFromVersion(latestVersion);
|
|
2007
|
+
const changedFields = getChangedFields(previousConfig, providedConfig);
|
|
2008
|
+
if (changedFields.length === 0) return false;
|
|
2009
|
+
await store.createVersion({
|
|
2010
|
+
...previousConfig,
|
|
2011
|
+
...providedConfig,
|
|
2012
|
+
id: crypto.randomUUID(),
|
|
2013
|
+
blockId,
|
|
2014
|
+
versionNumber: latestVersion.versionNumber + 1,
|
|
2015
|
+
changedFields,
|
|
2016
|
+
changeMessage: "Auto-saved after edit"
|
|
2017
|
+
});
|
|
2018
|
+
return true;
|
|
2019
|
+
} catch (error) {
|
|
2020
|
+
lastError = error;
|
|
2021
|
+
if (isVersionNumberConflictError2(error) && attempt < maxRetries - 1) {
|
|
2022
|
+
await new Promise((resolve) => setTimeout(resolve, 10 * (attempt + 1)));
|
|
2023
|
+
continue;
|
|
2024
|
+
}
|
|
2025
|
+
throw error;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
throw lastError;
|
|
2029
|
+
}
|
|
1774
2030
|
var EditorPromptNamespace = class extends CrudEditorNamespace {
|
|
1775
2031
|
onCacheEvict(id) {
|
|
1776
2032
|
this.mastra?.removePromptBlock(id);
|
|
@@ -1789,6 +2045,33 @@ var EditorPromptNamespace = class extends CrudEditorNamespace {
|
|
|
1789
2045
|
listResolved: (args) => store.listResolved(args)
|
|
1790
2046
|
};
|
|
1791
2047
|
}
|
|
2048
|
+
async update(input) {
|
|
2049
|
+
this.ensureRegistered();
|
|
2050
|
+
const storage = this.mastra?.getStorage();
|
|
2051
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
2052
|
+
const store = await storage.getStore("promptBlocks");
|
|
2053
|
+
if (!store) throw new Error("Prompt blocks storage domain is not available");
|
|
2054
|
+
const existing = await store.getById(input.id);
|
|
2055
|
+
if (!existing) {
|
|
2056
|
+
throw new Error(`Prompt block with id ${input.id} not found`);
|
|
2057
|
+
}
|
|
2058
|
+
const providedConfig = getProvidedConfigFields(input);
|
|
2059
|
+
if (Object.keys(providedConfig).length > 0) {
|
|
2060
|
+
await createPromptBlockVersionWithRetry(store, input.id, providedConfig);
|
|
2061
|
+
}
|
|
2062
|
+
const recordFields = getProvidedRecordFields(input);
|
|
2063
|
+
if (recordFields) {
|
|
2064
|
+
await store.update(recordFields);
|
|
2065
|
+
}
|
|
2066
|
+
this._cache.delete(input.id);
|
|
2067
|
+
this.onCacheEvict(input.id);
|
|
2068
|
+
const resolved = await store.getByIdResolved(input.id, { status: "draft" });
|
|
2069
|
+
if (!resolved) {
|
|
2070
|
+
throw new Error(`Failed to resolve entity ${input.id} after update`);
|
|
2071
|
+
}
|
|
2072
|
+
this._cache.set(input.id, resolved);
|
|
2073
|
+
return resolved;
|
|
2074
|
+
}
|
|
1792
2075
|
async preview(blocks, context) {
|
|
1793
2076
|
this.ensureRegistered();
|
|
1794
2077
|
const storage = this.mastra?.getStorage();
|