@memberjunction/ai-agent-manager 6.1.4 → 6.2.0-edge.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +107 -61
- package/dist/agent-spec-sync.d.ts +17 -1
- package/dist/agent-spec-sync.d.ts.map +1 -1
- package/dist/agent-spec-sync.js +121 -89
- package/dist/agent-spec-sync.js.map +1 -1
- package/package.json +9 -9
- package/src/agent-spec-sync.ts +129 -90
package/dist/agent-spec-sync.js
CHANGED
|
@@ -51,6 +51,14 @@ import { UUIDsEqual } from '@memberjunction/global';
|
|
|
51
51
|
* @module @memberjunction/ai-agent-manager
|
|
52
52
|
*/
|
|
53
53
|
export class AgentSpecSync {
|
|
54
|
+
/** @deprecated Use {@link Spec}. */
|
|
55
|
+
get spec() {
|
|
56
|
+
return this.Spec;
|
|
57
|
+
}
|
|
58
|
+
/** @deprecated Use {@link Spec}. */
|
|
59
|
+
set spec(value) {
|
|
60
|
+
this.Spec = value;
|
|
61
|
+
}
|
|
54
62
|
/**
|
|
55
63
|
* Returns the metadata provider to use for entity operations. Prefers a
|
|
56
64
|
* caller-supplied provider for server isolation; otherwise falls back to
|
|
@@ -87,12 +95,12 @@ export class AgentSpecSync {
|
|
|
87
95
|
*/
|
|
88
96
|
this._mutations = [];
|
|
89
97
|
if (spec) {
|
|
90
|
-
this.
|
|
98
|
+
this.Spec = this.initializeSpec(spec);
|
|
91
99
|
this._isDirty = true;
|
|
92
100
|
}
|
|
93
101
|
else {
|
|
94
102
|
// Create minimal empty spec
|
|
95
|
-
this.
|
|
103
|
+
this.Spec = {
|
|
96
104
|
ID: '', // Will be set on save if empty
|
|
97
105
|
Name: '',
|
|
98
106
|
StartingPayloadValidationMode: 'Fail',
|
|
@@ -120,15 +128,23 @@ export class AgentSpecSync {
|
|
|
120
128
|
* Get all mutations tracked during the last save operation
|
|
121
129
|
* @returns Array of mutations
|
|
122
130
|
*/
|
|
123
|
-
|
|
131
|
+
GetMutations() {
|
|
124
132
|
return [...this._mutations];
|
|
125
133
|
}
|
|
134
|
+
/** @deprecated Use {@link GetMutations}. */
|
|
135
|
+
getMutations() {
|
|
136
|
+
return this.GetMutations();
|
|
137
|
+
}
|
|
126
138
|
/**
|
|
127
139
|
* Clear all tracked mutations
|
|
128
140
|
*/
|
|
129
|
-
|
|
141
|
+
ClearMutations() {
|
|
130
142
|
this._mutations = [];
|
|
131
143
|
}
|
|
144
|
+
/** @deprecated Use {@link ClearMutations}. */
|
|
145
|
+
clearMutations() {
|
|
146
|
+
return this.ClearMutations();
|
|
147
|
+
}
|
|
132
148
|
// ===== STATIC FACTORY METHODS =====
|
|
133
149
|
/**
|
|
134
150
|
* Load an agent and its complete hierarchy from the database by ID.
|
|
@@ -342,11 +358,11 @@ export class AgentSpecSync {
|
|
|
342
358
|
};
|
|
343
359
|
}
|
|
344
360
|
// Step 3: Map entities to raw spec format
|
|
345
|
-
this.
|
|
361
|
+
this.Spec = this.mapEntitiesToRawSpec(agentEntity, actionsResult.Results || [], childAgentsResult.Results || [], relatedAgentsResult.Results || [], promptsResult.Results || [], fullPromptsResult.Results || [], stepsResult.Results || [], pathsResult.Results || []);
|
|
346
362
|
// Step 4: Recursively load sub-agents if requested
|
|
347
|
-
if (includeSubAgents && this.
|
|
363
|
+
if (includeSubAgents && this.Spec.SubAgents && this.Spec.SubAgents.length > 0) {
|
|
348
364
|
// Recursively load complete specs for all sub-agents
|
|
349
|
-
for (const subAgentSpec of this.
|
|
365
|
+
for (const subAgentSpec of this.Spec.SubAgents) {
|
|
350
366
|
if (subAgentSpec.SubAgent && subAgentSpec.SubAgent.ID) {
|
|
351
367
|
try {
|
|
352
368
|
// Load the complete sub-agent spec recursively
|
|
@@ -604,22 +620,22 @@ export class AgentSpecSync {
|
|
|
604
620
|
*/
|
|
605
621
|
async SaveToDatabase(validate = true) {
|
|
606
622
|
// Clear previous mutations
|
|
607
|
-
this.
|
|
623
|
+
this.ClearMutations();
|
|
608
624
|
if (!this._isDirty && this._isLoaded) {
|
|
609
625
|
// No changes to save
|
|
610
626
|
return {
|
|
611
|
-
agentId: this.
|
|
627
|
+
agentId: this.Spec.ID,
|
|
612
628
|
success: true,
|
|
613
629
|
mutations: []
|
|
614
630
|
};
|
|
615
631
|
}
|
|
616
632
|
try {
|
|
617
633
|
// Step 0: Delete orphaned records (if this is an update)
|
|
618
|
-
if (this._isLoaded && this.
|
|
619
|
-
console.log(`🗑️ SaveToDatabase: Loading current database state for agent ${this.
|
|
620
|
-
const dbState = await this.loadCurrentDatabaseState(this.
|
|
634
|
+
if (this._isLoaded && this.Spec.ID) {
|
|
635
|
+
console.log(`🗑️ SaveToDatabase: Loading current database state for agent ${this.Spec.ID}...`);
|
|
636
|
+
const dbState = await this.loadCurrentDatabaseState(this.Spec.ID);
|
|
621
637
|
console.log(`🔍 SaveToDatabase: Identifying orphaned records...`);
|
|
622
|
-
const orphans = this.identifyOrphans(dbState, this.
|
|
638
|
+
const orphans = this.identifyOrphans(dbState, this.Spec);
|
|
623
639
|
console.log(`🗑️ SaveToDatabase: Deleting ${orphans.paths.length} paths, ${orphans.actions.length} actions, ${orphans.steps.length} steps, ${orphans.prompts.length} prompts, ${orphans.relationships.length} relationships, orphaning ${orphans.childAgents.length} child agents...`);
|
|
624
640
|
await this.deleteOrphans(orphans);
|
|
625
641
|
console.log(`✅ SaveToDatabase: Orphan cleanup complete`);
|
|
@@ -641,15 +657,15 @@ export class AgentSpecSync {
|
|
|
641
657
|
return {
|
|
642
658
|
agentId,
|
|
643
659
|
success: true,
|
|
644
|
-
mutations: this.
|
|
660
|
+
mutations: this.GetMutations()
|
|
645
661
|
};
|
|
646
662
|
}
|
|
647
663
|
catch (error) {
|
|
648
664
|
// Return failure with whatever mutations were completed before error
|
|
649
665
|
return {
|
|
650
|
-
agentId: this.
|
|
666
|
+
agentId: this.Spec.ID || '',
|
|
651
667
|
success: false,
|
|
652
|
-
mutations: this.
|
|
668
|
+
mutations: this.GetMutations()
|
|
653
669
|
};
|
|
654
670
|
}
|
|
655
671
|
}
|
|
@@ -665,69 +681,69 @@ export class AgentSpecSync {
|
|
|
665
681
|
const md = this.providerToUse;
|
|
666
682
|
const agentEntity = await md.GetEntityObject('MJ: AI Agents', this._contextUser);
|
|
667
683
|
// Track if this is an update or create
|
|
668
|
-
const isUpdate = !!this.
|
|
684
|
+
const isUpdate = !!this.Spec.ID;
|
|
669
685
|
// If ID exists, load existing record
|
|
670
|
-
if (this.
|
|
671
|
-
const loaded = await agentEntity.Load(this.
|
|
686
|
+
if (this.Spec.ID) {
|
|
687
|
+
const loaded = await agentEntity.Load(this.Spec.ID);
|
|
672
688
|
if (!loaded) {
|
|
673
|
-
throw new Error(`Cannot update non-existent agent with ID ${this.
|
|
689
|
+
throw new Error(`Cannot update non-existent agent with ID ${this.Spec.ID}`);
|
|
674
690
|
}
|
|
675
691
|
}
|
|
676
692
|
// Map spec to entity fields
|
|
677
|
-
agentEntity.Name = this.
|
|
678
|
-
agentEntity.Description = this.
|
|
679
|
-
agentEntity.IconClass = this.
|
|
680
|
-
agentEntity.LogoURL = this.
|
|
681
|
-
agentEntity.ParentID = this.
|
|
682
|
-
agentEntity.DriverClass = this.
|
|
683
|
-
agentEntity.ModelSelectionMode = this.
|
|
693
|
+
agentEntity.Name = this.Spec.Name;
|
|
694
|
+
agentEntity.Description = this.Spec.Description || null;
|
|
695
|
+
agentEntity.IconClass = this.Spec.IconClass || null;
|
|
696
|
+
agentEntity.LogoURL = this.Spec.LogoURL || null;
|
|
697
|
+
agentEntity.ParentID = this.Spec.ParentID || null;
|
|
698
|
+
agentEntity.DriverClass = this.Spec.DriverClass || null;
|
|
699
|
+
agentEntity.ModelSelectionMode = this.Spec.ModelSelectionMode || 'Agent Type';
|
|
684
700
|
// Handle TypeID - supports lookup references or direct GUID
|
|
685
|
-
if (this.
|
|
686
|
-
agentEntity.TypeID = this.
|
|
701
|
+
if (this.Spec.TypeID) {
|
|
702
|
+
agentEntity.TypeID = this.Spec.TypeID;
|
|
687
703
|
}
|
|
688
704
|
// Handle Status - defaults to Active if not specified. Typed rather than cast: the cast is
|
|
689
705
|
// what let `'Inactive'` — a value the CHECK constraint rejects — reach the entity unchallenged.
|
|
690
|
-
agentEntity.Status = this.
|
|
706
|
+
agentEntity.Status = this.Spec.Status ?? 'Active';
|
|
691
707
|
// Serialize JSON fields
|
|
692
|
-
agentEntity.PayloadDownstreamPaths = JSON.stringify(this.
|
|
693
|
-
agentEntity.PayloadUpstreamPaths = JSON.stringify(this.
|
|
694
|
-
agentEntity.PayloadSelfReadPaths = this.
|
|
695
|
-
? JSON.stringify(this.
|
|
708
|
+
agentEntity.PayloadDownstreamPaths = JSON.stringify(this.Spec.PayloadDownstreamPaths || ['*']);
|
|
709
|
+
agentEntity.PayloadUpstreamPaths = JSON.stringify(this.Spec.PayloadUpstreamPaths || ['*']);
|
|
710
|
+
agentEntity.PayloadSelfReadPaths = this.Spec.PayloadSelfReadPaths
|
|
711
|
+
? JSON.stringify(this.Spec.PayloadSelfReadPaths)
|
|
696
712
|
: null;
|
|
697
|
-
agentEntity.PayloadSelfWritePaths = this.
|
|
698
|
-
? JSON.stringify(this.
|
|
713
|
+
agentEntity.PayloadSelfWritePaths = this.Spec.PayloadSelfWritePaths
|
|
714
|
+
? JSON.stringify(this.Spec.PayloadSelfWritePaths)
|
|
699
715
|
: null;
|
|
700
|
-
agentEntity.PayloadScope = this.
|
|
716
|
+
agentEntity.PayloadScope = this.Spec.PayloadScope || null;
|
|
701
717
|
// Validation fields
|
|
702
|
-
agentEntity.FinalPayloadValidation = this.
|
|
703
|
-
agentEntity.FinalPayloadValidationMode = this.
|
|
704
|
-
agentEntity.FinalPayloadValidationMaxRetries = this.
|
|
705
|
-
agentEntity.StartingPayloadValidation = this.
|
|
706
|
-
agentEntity.StartingPayloadValidationMode = this.
|
|
718
|
+
agentEntity.FinalPayloadValidation = this.Spec.FinalPayloadValidation || null;
|
|
719
|
+
agentEntity.FinalPayloadValidationMode = this.Spec.FinalPayloadValidationMode || 'Retry';
|
|
720
|
+
agentEntity.FinalPayloadValidationMaxRetries = this.Spec.FinalPayloadValidationMaxRetries || 3;
|
|
721
|
+
agentEntity.StartingPayloadValidation = this.Spec.StartingPayloadValidation || null;
|
|
722
|
+
agentEntity.StartingPayloadValidationMode = this.Spec.StartingPayloadValidationMode || 'Fail';
|
|
707
723
|
// Resource limits
|
|
708
|
-
agentEntity.MaxCostPerRun = this.
|
|
709
|
-
agentEntity.MaxTokensPerRun = this.
|
|
710
|
-
agentEntity.MaxIterationsPerRun = this.
|
|
711
|
-
agentEntity.MaxTimePerRun = this.
|
|
724
|
+
agentEntity.MaxCostPerRun = this.Spec.MaxCostPerRun || null;
|
|
725
|
+
agentEntity.MaxTokensPerRun = this.Spec.MaxTokensPerRun || null;
|
|
726
|
+
agentEntity.MaxIterationsPerRun = this.Spec.MaxIterationsPerRun || null;
|
|
727
|
+
agentEntity.MaxTimePerRun = this.Spec.MaxTimePerRun || null;
|
|
712
728
|
// Execution frequency
|
|
713
|
-
agentEntity.MinExecutionsPerRun = this.
|
|
714
|
-
agentEntity.MaxExecutionsPerRun = this.
|
|
729
|
+
agentEntity.MinExecutionsPerRun = this.Spec.MinExecutionsPerRun || null;
|
|
730
|
+
agentEntity.MaxExecutionsPerRun = this.Spec.MaxExecutionsPerRun || null;
|
|
715
731
|
// Other config
|
|
716
|
-
agentEntity.DefaultPromptEffortLevel = this.
|
|
717
|
-
agentEntity.ChatHandlingOption = this.
|
|
718
|
-
agentEntity.DefaultArtifactTypeID = this.
|
|
732
|
+
agentEntity.DefaultPromptEffortLevel = this.Spec.DefaultPromptEffortLevel || null;
|
|
733
|
+
agentEntity.ChatHandlingOption = this.Spec.ChatHandlingOption || null;
|
|
734
|
+
agentEntity.DefaultArtifactTypeID = this.Spec.DefaultArtifactTypeID || null;
|
|
719
735
|
// Set OwnerUserID - always use contextUser if available (user creating/modifying the agent)
|
|
720
736
|
if (this._contextUser) {
|
|
721
737
|
agentEntity.OwnerUserID = this._contextUser.ID;
|
|
722
738
|
}
|
|
723
|
-
else if (this.
|
|
739
|
+
else if (this.Spec.OwnerUserID) {
|
|
724
740
|
// Fallback to spec value if no contextUser provided
|
|
725
|
-
agentEntity.OwnerUserID = this.
|
|
741
|
+
agentEntity.OwnerUserID = this.Spec.OwnerUserID;
|
|
726
742
|
}
|
|
727
|
-
agentEntity.InvocationMode = this.
|
|
743
|
+
agentEntity.InvocationMode = this.Spec.InvocationMode || 'Any';
|
|
728
744
|
// Requirements and design documentation
|
|
729
|
-
agentEntity.FunctionalRequirements = this.
|
|
730
|
-
agentEntity.TechnicalDesign = this.
|
|
745
|
+
agentEntity.FunctionalRequirements = this.Spec.FunctionalRequirements || null;
|
|
746
|
+
agentEntity.TechnicalDesign = this.Spec.TechnicalDesign || null;
|
|
731
747
|
// Validate if requested
|
|
732
748
|
if (validate) {
|
|
733
749
|
const validation = agentEntity.Validate();
|
|
@@ -742,9 +758,9 @@ export class AgentSpecSync {
|
|
|
742
758
|
throw new Error('Failed to save agent entity');
|
|
743
759
|
}
|
|
744
760
|
// Update spec with saved ID
|
|
745
|
-
this.
|
|
761
|
+
this.Spec.ID = agentEntity.ID;
|
|
746
762
|
// Track the mutation
|
|
747
|
-
this.trackMutation('MJ: AI Agents', isUpdate ? 'Update' : 'Create', agentEntity.ID, `${isUpdate ? 'Updated' : 'Created'} agent: ${this.
|
|
763
|
+
this.trackMutation('MJ: AI Agents', isUpdate ? 'Update' : 'Create', agentEntity.ID, `${isUpdate ? 'Updated' : 'Created'} agent: ${this.Spec.Name}`);
|
|
748
764
|
return agentEntity.ID;
|
|
749
765
|
}
|
|
750
766
|
/**
|
|
@@ -759,11 +775,11 @@ export class AgentSpecSync {
|
|
|
759
775
|
* @throws {Error} If any action save fails
|
|
760
776
|
*/
|
|
761
777
|
async saveActions(agentId) {
|
|
762
|
-
if (!this.
|
|
778
|
+
if (!this.Spec.Actions || this.Spec.Actions.length === 0) {
|
|
763
779
|
return;
|
|
764
780
|
}
|
|
765
781
|
const md = this.providerToUse;
|
|
766
|
-
for (const actionSpec of this.
|
|
782
|
+
for (const actionSpec of this.Spec.Actions) {
|
|
767
783
|
const actionEntity = await md.GetEntityObject('MJ: AI Agent Actions', this._contextUser);
|
|
768
784
|
// Track if this is an update or create
|
|
769
785
|
const isUpdate = !!actionSpec.AgentActionID;
|
|
@@ -803,10 +819,10 @@ export class AgentSpecSync {
|
|
|
803
819
|
* @throws {Error} If any sub-agent save fails
|
|
804
820
|
*/
|
|
805
821
|
async saveSubAgents(agentId) {
|
|
806
|
-
if (!this.
|
|
822
|
+
if (!this.Spec.SubAgents || this.Spec.SubAgents.length === 0) {
|
|
807
823
|
return;
|
|
808
824
|
}
|
|
809
|
-
for (const SubAgentSpec of this.
|
|
825
|
+
for (const SubAgentSpec of this.Spec.SubAgents) {
|
|
810
826
|
if (SubAgentSpec.Type === 'child') {
|
|
811
827
|
await this.saveChildSubAgent(agentId, SubAgentSpec);
|
|
812
828
|
}
|
|
@@ -928,17 +944,17 @@ export class AgentSpecSync {
|
|
|
928
944
|
* @throws {Error} If any prompt save fails
|
|
929
945
|
*/
|
|
930
946
|
async savePrompts(agentId) {
|
|
931
|
-
console.log(`💬 savePrompts: Called with agentId=${agentId}, Prompts=${this.
|
|
932
|
-
if (!this.
|
|
947
|
+
console.log(`💬 savePrompts: Called with agentId=${agentId}, Prompts=${this.Spec.Prompts ? this.Spec.Prompts.length : 'undefined'}`);
|
|
948
|
+
if (!this.Spec.Prompts || this.Spec.Prompts.length === 0) {
|
|
933
949
|
console.log('💬 savePrompts: No prompts to save, returning early');
|
|
934
950
|
return;
|
|
935
951
|
}
|
|
936
|
-
console.log(`💬 savePrompts: Processing ${this.
|
|
952
|
+
console.log(`💬 savePrompts: Processing ${this.Spec.Prompts.length} prompt(s)...`);
|
|
937
953
|
const md = this.providerToUse;
|
|
938
954
|
const rv = RunView.FromMetadataProvider(this._provider);
|
|
939
955
|
// Step 1: Create or update AIPrompt records
|
|
940
|
-
for (let i = 0; i < this.
|
|
941
|
-
const promptSpec = this.
|
|
956
|
+
for (let i = 0; i < this.Spec.Prompts.length; i++) {
|
|
957
|
+
const promptSpec = this.Spec.Prompts[i];
|
|
942
958
|
// Check if this is an update (has PromptID) or create (no PromptID)
|
|
943
959
|
let promptEntity = await md.GetEntityObject('MJ: AI Prompts', this._contextUser);
|
|
944
960
|
let isUpdate = false;
|
|
@@ -954,8 +970,8 @@ export class AgentSpecSync {
|
|
|
954
970
|
}
|
|
955
971
|
}
|
|
956
972
|
// Set all required fields (both create and update)
|
|
957
|
-
promptEntity.Name = `${this.
|
|
958
|
-
promptEntity.Description = `Agent prompt ${i + 1} for ${this.
|
|
973
|
+
promptEntity.Name = `${this.Spec.Name} - Prompt ${i + 1}`;
|
|
974
|
+
promptEntity.Description = `Agent prompt ${i + 1} for ${this.Spec.Name}`;
|
|
959
975
|
promptEntity.TypeID = 'a6da423e-f36b-1410-8dac-00021f8b792e'; // Chat type
|
|
960
976
|
promptEntity.Status = 'Active';
|
|
961
977
|
promptEntity.ResponseFormat = 'JSON';
|
|
@@ -981,7 +997,7 @@ export class AgentSpecSync {
|
|
|
981
997
|
}
|
|
982
998
|
const saved = await promptEntity.Save();
|
|
983
999
|
if (!saved) {
|
|
984
|
-
throw new Error(`Failed to save prompt ${i + 1} for agent ${this.
|
|
1000
|
+
throw new Error(`Failed to save prompt ${i + 1} for agent ${this.Spec.Name}`);
|
|
985
1001
|
}
|
|
986
1002
|
// Track mutation
|
|
987
1003
|
this.trackMutation('MJ: AI Prompts', isUpdate ? 'Update' : 'Create', promptEntity.ID, `${isUpdate ? 'Updated' : 'Created'} prompt: ${promptEntity.Name}`);
|
|
@@ -1021,7 +1037,7 @@ export class AgentSpecSync {
|
|
|
1021
1037
|
this.trackMutation('MJ: AI Agent Prompts', isJunctionUpdate ? 'Update' : 'Create', agentPromptEntity.ID, `${isJunctionUpdate ? 'Updated' : 'Created'} agent-prompt junction for prompt ${promptEntity.ID}`);
|
|
1022
1038
|
console.log(`✅ savePrompts: ${isJunctionUpdate ? 'Updated' : 'Created'} AIAgentPrompt junction with ID: ${agentPromptEntity.ID}`);
|
|
1023
1039
|
}
|
|
1024
|
-
console.log(`✅ savePrompts: Successfully saved all ${this.
|
|
1040
|
+
console.log(`✅ savePrompts: Successfully saved all ${this.Spec.Prompts.length} prompt(s)`);
|
|
1025
1041
|
}
|
|
1026
1042
|
/**
|
|
1027
1043
|
* Save all steps for this agent (Flow agents only).
|
|
@@ -1034,14 +1050,14 @@ export class AgentSpecSync {
|
|
|
1034
1050
|
* @throws {Error} If any step save fails
|
|
1035
1051
|
*/
|
|
1036
1052
|
async saveSteps(agentId) {
|
|
1037
|
-
console.log(`🔷 saveSteps: Called with agentId=${agentId}, Steps=${this.
|
|
1038
|
-
if (!this.
|
|
1053
|
+
console.log(`🔷 saveSteps: Called with agentId=${agentId}, Steps=${this.Spec.Steps ? this.Spec.Steps.length : 'undefined'}`);
|
|
1054
|
+
if (!this.Spec.Steps || this.Spec.Steps.length === 0) {
|
|
1039
1055
|
console.log('🔷 saveSteps: No steps to save, returning early');
|
|
1040
1056
|
return;
|
|
1041
1057
|
}
|
|
1042
|
-
console.log(`🔷 saveSteps: Processing ${this.
|
|
1058
|
+
console.log(`🔷 saveSteps: Processing ${this.Spec.Steps.length} step(s)...`);
|
|
1043
1059
|
const md = this.providerToUse;
|
|
1044
|
-
for (const stepSpec of this.
|
|
1060
|
+
for (const stepSpec of this.Spec.Steps) {
|
|
1045
1061
|
const stepEntity = await md.GetEntityObject('MJ: AI Agent Steps', this._contextUser);
|
|
1046
1062
|
// Load existing if ID provided
|
|
1047
1063
|
const isUpdate = !!(stepSpec.ID && stepSpec.ID !== '');
|
|
@@ -1116,7 +1132,7 @@ export class AgentSpecSync {
|
|
|
1116
1132
|
}
|
|
1117
1133
|
const saved = await stepEntity.Save();
|
|
1118
1134
|
if (!saved) {
|
|
1119
|
-
throw new Error(`Failed to save step "${stepSpec.Name}" for agent ${this.
|
|
1135
|
+
throw new Error(`Failed to save step "${stepSpec.Name}" for agent ${this.Spec.Name}`);
|
|
1120
1136
|
}
|
|
1121
1137
|
// Track mutation
|
|
1122
1138
|
this.trackMutation('AI Agent Steps', isUpdate ? 'Update' : 'Create', stepEntity.ID, `${isUpdate ? 'Updated' : 'Created'} step: ${stepSpec.Name}`);
|
|
@@ -1124,7 +1140,7 @@ export class AgentSpecSync {
|
|
|
1124
1140
|
stepSpec.ID = stepEntity.ID;
|
|
1125
1141
|
console.log(`✅ saveSteps: Created AIAgentStep with ID: ${stepEntity.ID}`);
|
|
1126
1142
|
}
|
|
1127
|
-
console.log(`✅ saveSteps: Successfully saved all ${this.
|
|
1143
|
+
console.log(`✅ saveSteps: Successfully saved all ${this.Spec.Steps.length} step(s)`);
|
|
1128
1144
|
}
|
|
1129
1145
|
/**
|
|
1130
1146
|
* Save all step paths for this agent (Flow agents only).
|
|
@@ -1137,23 +1153,23 @@ export class AgentSpecSync {
|
|
|
1137
1153
|
* @throws {Error} If any path save fails
|
|
1138
1154
|
*/
|
|
1139
1155
|
async saveStepPaths(agentId) {
|
|
1140
|
-
console.log(`🔶 saveStepPaths: Called with agentId=${agentId}, Paths=${this.
|
|
1141
|
-
if (!this.
|
|
1156
|
+
console.log(`🔶 saveStepPaths: Called with agentId=${agentId}, Paths=${this.Spec.Paths ? this.Spec.Paths.length : 'undefined'}`);
|
|
1157
|
+
if (!this.Spec.Paths || this.Spec.Paths.length === 0) {
|
|
1142
1158
|
console.log('🔶 saveStepPaths: No paths to save, returning early');
|
|
1143
1159
|
return;
|
|
1144
1160
|
}
|
|
1145
|
-
console.log(`🔶 saveStepPaths: Processing ${this.
|
|
1161
|
+
console.log(`🔶 saveStepPaths: Processing ${this.Spec.Paths.length} path(s)...`);
|
|
1146
1162
|
const md = this.providerToUse;
|
|
1147
1163
|
// Create a map of step names to IDs for easy lookup
|
|
1148
1164
|
const stepNameToId = new Map();
|
|
1149
|
-
if (this.
|
|
1150
|
-
for (const step of this.
|
|
1165
|
+
if (this.Spec.Steps) {
|
|
1166
|
+
for (const step of this.Spec.Steps) {
|
|
1151
1167
|
if (step.ID) {
|
|
1152
1168
|
stepNameToId.set(step.Name, step.ID);
|
|
1153
1169
|
}
|
|
1154
1170
|
}
|
|
1155
1171
|
}
|
|
1156
|
-
for (const pathSpec of this.
|
|
1172
|
+
for (const pathSpec of this.Spec.Paths) {
|
|
1157
1173
|
const pathEntity = await md.GetEntityObject('MJ: AI Agent Step Paths', this._contextUser);
|
|
1158
1174
|
// Load existing if ID provided
|
|
1159
1175
|
const isUpdate = !!(pathSpec.ID && pathSpec.ID !== '');
|
|
@@ -1188,7 +1204,7 @@ export class AgentSpecSync {
|
|
|
1188
1204
|
pathSpec.ID = pathEntity.ID;
|
|
1189
1205
|
console.log(`✅ saveStepPaths: Created AIAgentStepPath with ID: ${pathEntity.ID}`);
|
|
1190
1206
|
}
|
|
1191
|
-
console.log(`✅ saveStepPaths: Successfully saved all ${this.
|
|
1207
|
+
console.log(`✅ saveStepPaths: Successfully saved all ${this.Spec.Paths.length} path(s)`);
|
|
1192
1208
|
}
|
|
1193
1209
|
// ===== UTILITY METHODS =====
|
|
1194
1210
|
/**
|
|
@@ -1283,24 +1299,32 @@ export class AgentSpecSync {
|
|
|
1283
1299
|
* ```
|
|
1284
1300
|
*/
|
|
1285
1301
|
toJSON() {
|
|
1286
|
-
return { ...this.
|
|
1302
|
+
return { ...this.Spec };
|
|
1287
1303
|
}
|
|
1288
1304
|
/**
|
|
1289
1305
|
* Check if this spec has unsaved changes.
|
|
1290
1306
|
*
|
|
1291
1307
|
* @returns True if there are unsaved changes, false otherwise
|
|
1292
1308
|
*/
|
|
1293
|
-
get
|
|
1309
|
+
get IsDirty() {
|
|
1294
1310
|
return this._isDirty;
|
|
1295
1311
|
}
|
|
1312
|
+
/** @deprecated Use {@link IsDirty}. */
|
|
1313
|
+
get isDirty() {
|
|
1314
|
+
return this.IsDirty;
|
|
1315
|
+
}
|
|
1296
1316
|
/**
|
|
1297
1317
|
* Check if this spec has been loaded from the database.
|
|
1298
1318
|
*
|
|
1299
1319
|
* @returns True if loaded from database, false if created in memory
|
|
1300
1320
|
*/
|
|
1301
|
-
get
|
|
1321
|
+
get IsLoaded() {
|
|
1302
1322
|
return this._isLoaded;
|
|
1303
1323
|
}
|
|
1324
|
+
/** @deprecated Use {@link IsLoaded}. */
|
|
1325
|
+
get isLoaded() {
|
|
1326
|
+
return this.IsLoaded;
|
|
1327
|
+
}
|
|
1304
1328
|
/**
|
|
1305
1329
|
* Mark the spec as having changes.
|
|
1306
1330
|
*
|
|
@@ -1316,9 +1340,13 @@ export class AgentSpecSync {
|
|
|
1316
1340
|
* await spec.SaveToDatabase();
|
|
1317
1341
|
* ```
|
|
1318
1342
|
*/
|
|
1319
|
-
|
|
1343
|
+
MarkDirty() {
|
|
1320
1344
|
this._isDirty = true;
|
|
1321
1345
|
}
|
|
1346
|
+
/** @deprecated Use {@link MarkDirty}. */
|
|
1347
|
+
markDirty() {
|
|
1348
|
+
return this.MarkDirty();
|
|
1349
|
+
}
|
|
1322
1350
|
/**
|
|
1323
1351
|
* Mark the spec as having been loaded from the database.
|
|
1324
1352
|
*
|
|
@@ -1336,9 +1364,13 @@ export class AgentSpecSync {
|
|
|
1336
1364
|
* await childSync.SaveToDatabase();
|
|
1337
1365
|
* ```
|
|
1338
1366
|
*/
|
|
1339
|
-
|
|
1367
|
+
MarkLoaded() {
|
|
1340
1368
|
this._isLoaded = true;
|
|
1341
1369
|
}
|
|
1370
|
+
/** @deprecated Use {@link MarkLoaded}. */
|
|
1371
|
+
markLoaded() {
|
|
1372
|
+
return this.MarkLoaded();
|
|
1373
|
+
}
|
|
1342
1374
|
// ===== DELETE/ORPHAN METHODS =====
|
|
1343
1375
|
/**
|
|
1344
1376
|
* Load the current state of all agent-related records from the database.
|