@memberjunction/ai-agent-manager 2.109.0 → 2.110.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 +28 -0
- package/dist/agent-spec-sync.d.ts +99 -4
- package/dist/agent-spec-sync.d.ts.map +1 -1
- package/dist/agent-spec-sync.js +503 -56
- package/dist/agent-spec-sync.js.map +1 -1
- package/dist/agents/architect-agent.d.ts +1 -1
- package/dist/agents/architect-agent.d.ts.map +1 -1
- package/dist/agents/architect-agent.js +147 -10
- package/dist/agents/architect-agent.js.map +1 -1
- package/dist/agents/builder-agent.d.ts +4 -2
- package/dist/agents/builder-agent.d.ts.map +1 -1
- package/dist/agents/builder-agent.js +64 -17
- package/dist/agents/builder-agent.js.map +1 -1
- package/dist/old/agent-definition.interface.d.ts +64 -0
- package/dist/old/agent-definition.interface.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/agent-spec-sync.ts +664 -62
- package/src/agents/architect-agent.ts +164 -10
- package/src/agents/builder-agent.ts +82 -20
- package/src/old/agent-definition.interface.ts +59 -0
package/dist/agent-spec-sync.js
CHANGED
|
@@ -75,6 +75,11 @@ class AgentSpecSync {
|
|
|
75
75
|
* @private
|
|
76
76
|
*/
|
|
77
77
|
this._isDirty = false;
|
|
78
|
+
/**
|
|
79
|
+
* Tracks all database mutations performed during save operations
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
this._mutations = [];
|
|
78
83
|
if (spec) {
|
|
79
84
|
this.spec = this.initializeSpec(spec);
|
|
80
85
|
this._isDirty = true;
|
|
@@ -91,6 +96,32 @@ class AgentSpecSync {
|
|
|
91
96
|
}
|
|
92
97
|
this._contextUser = contextUser;
|
|
93
98
|
}
|
|
99
|
+
// ===== MUTATION TRACKING METHODS =====
|
|
100
|
+
/**
|
|
101
|
+
* Track a database mutation performed during save operation
|
|
102
|
+
* @private
|
|
103
|
+
*/
|
|
104
|
+
trackMutation(entity, operation, id, description) {
|
|
105
|
+
this._mutations.push({
|
|
106
|
+
Entity: entity,
|
|
107
|
+
Operation: operation,
|
|
108
|
+
ID: id,
|
|
109
|
+
Description: description
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get all mutations tracked during the last save operation
|
|
114
|
+
* @returns Array of mutations
|
|
115
|
+
*/
|
|
116
|
+
getMutations() {
|
|
117
|
+
return [...this._mutations];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Clear all tracked mutations
|
|
121
|
+
*/
|
|
122
|
+
clearMutations() {
|
|
123
|
+
this._mutations = [];
|
|
124
|
+
}
|
|
94
125
|
// ===== STATIC FACTORY METHODS =====
|
|
95
126
|
/**
|
|
96
127
|
* Load an agent and its complete hierarchy from the database by ID.
|
|
@@ -208,7 +239,8 @@ class AgentSpecSync {
|
|
|
208
239
|
throw new Error(`Agent with ID ${agentId} not found`);
|
|
209
240
|
}
|
|
210
241
|
// Step 2: Batch load related entities using RunViews for optimal performance
|
|
211
|
-
|
|
242
|
+
// Note: Load paths separately after steps to avoid hardcoded view name in subquery
|
|
243
|
+
const [actionsResult, childAgentsResult, relatedAgentsResult, promptsResult, stepsResult] = await rv.RunViews([
|
|
212
244
|
{
|
|
213
245
|
EntityName: 'AI Agent Actions',
|
|
214
246
|
ExtraFilter: `AgentID='${agentId}'`,
|
|
@@ -226,6 +258,18 @@ class AgentSpecSync {
|
|
|
226
258
|
ExtraFilter: `AgentID='${agentId}' AND Status='Active'`,
|
|
227
259
|
OrderBy: '__mj_CreatedAt',
|
|
228
260
|
ResultType: 'entity_object'
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
EntityName: 'MJ: AI Agent Prompts',
|
|
264
|
+
ExtraFilter: `AgentID='${agentId}'`,
|
|
265
|
+
OrderBy: 'ExecutionOrder',
|
|
266
|
+
ResultType: 'entity_object'
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
EntityName: 'MJ: AI Agent Steps',
|
|
270
|
+
ExtraFilter: `AgentID='${agentId}'`,
|
|
271
|
+
OrderBy: 'Name',
|
|
272
|
+
ResultType: 'entity_object'
|
|
229
273
|
}
|
|
230
274
|
], this._contextUser);
|
|
231
275
|
// Check for errors
|
|
@@ -238,13 +282,84 @@ class AgentSpecSync {
|
|
|
238
282
|
if (!relatedAgentsResult.Success) {
|
|
239
283
|
throw new Error(`Failed to load related agents: ${relatedAgentsResult.ErrorMessage}`);
|
|
240
284
|
}
|
|
285
|
+
if (!promptsResult.Success) {
|
|
286
|
+
throw new Error(`Failed to load agent prompts: ${promptsResult.ErrorMessage}`);
|
|
287
|
+
}
|
|
288
|
+
if (!stepsResult.Success) {
|
|
289
|
+
throw new Error(`Failed to load agent steps: ${stepsResult.ErrorMessage}`);
|
|
290
|
+
}
|
|
291
|
+
// Step 2b: Load paths separately using step IDs to avoid hardcoded view name
|
|
292
|
+
let pathsResult;
|
|
293
|
+
const steps = stepsResult.Results || [];
|
|
294
|
+
if (steps.length > 0) {
|
|
295
|
+
const stepIds = steps.map((s) => `'${s.ID}'`).join(',');
|
|
296
|
+
pathsResult = await rv.RunView({
|
|
297
|
+
EntityName: 'MJ: AI Agent Step Paths',
|
|
298
|
+
ExtraFilter: `OriginStepID IN (${stepIds})`,
|
|
299
|
+
OrderBy: 'Priority DESC',
|
|
300
|
+
ResultType: 'entity_object'
|
|
301
|
+
}, this._contextUser);
|
|
302
|
+
if (!pathsResult.Success) {
|
|
303
|
+
throw new Error(`Failed to load step paths: ${pathsResult.ErrorMessage}`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
// No steps, so no paths
|
|
308
|
+
pathsResult = {
|
|
309
|
+
Success: true,
|
|
310
|
+
Results: [],
|
|
311
|
+
RowCount: 0
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
// Step 2c: Load full AI Prompt records to get PromptText, PromptRole, PromptPosition
|
|
315
|
+
let fullPromptsResult;
|
|
316
|
+
const agentPrompts = promptsResult.Results || [];
|
|
317
|
+
if (agentPrompts.length > 0) {
|
|
318
|
+
const promptIds = agentPrompts.map((p) => `'${p.PromptID}'`).join(',');
|
|
319
|
+
fullPromptsResult = await rv.RunView({
|
|
320
|
+
EntityName: 'AI Prompts',
|
|
321
|
+
ExtraFilter: `ID IN (${promptIds})`,
|
|
322
|
+
OrderBy: 'Name',
|
|
323
|
+
ResultType: 'entity_object'
|
|
324
|
+
}, this._contextUser);
|
|
325
|
+
if (!fullPromptsResult.Success) {
|
|
326
|
+
throw new Error(`Failed to load AI prompts: ${fullPromptsResult.ErrorMessage}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
// No prompts
|
|
331
|
+
fullPromptsResult = {
|
|
332
|
+
Success: true,
|
|
333
|
+
Results: [],
|
|
334
|
+
RowCount: 0
|
|
335
|
+
};
|
|
336
|
+
}
|
|
241
337
|
// Step 3: Map entities to raw spec format
|
|
242
|
-
this.spec = this.mapEntitiesToRawSpec(agentEntity, actionsResult.Results || [], childAgentsResult.Results || [], relatedAgentsResult.Results || []);
|
|
338
|
+
this.spec = this.mapEntitiesToRawSpec(agentEntity, actionsResult.Results || [], childAgentsResult.Results || [], relatedAgentsResult.Results || [], promptsResult.Results || [], fullPromptsResult.Results || [], stepsResult.Results || [], pathsResult.Results || []);
|
|
243
339
|
// Step 4: Recursively load sub-agents if requested
|
|
244
340
|
if (includeSubAgents && this.spec.SubAgents && this.spec.SubAgents.length > 0) {
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
341
|
+
// Recursively load complete specs for all sub-agents
|
|
342
|
+
for (const subAgentSpec of this.spec.SubAgents) {
|
|
343
|
+
if (subAgentSpec.SubAgent && subAgentSpec.SubAgent.ID) {
|
|
344
|
+
try {
|
|
345
|
+
// Load the complete sub-agent spec recursively
|
|
346
|
+
const subAgentSync = await AgentSpecSync.LoadFromDatabase(subAgentSpec.SubAgent.ID, this._contextUser, true // Recursively load nested sub-agents too
|
|
347
|
+
);
|
|
348
|
+
// Replace the minimal SubAgent with the complete spec
|
|
349
|
+
const fullSubAgentSpec = subAgentSync.toJSON();
|
|
350
|
+
// Preserve the relationship metadata while adding full spec details
|
|
351
|
+
subAgentSpec.SubAgent = {
|
|
352
|
+
...fullSubAgentSpec,
|
|
353
|
+
// Ensure we preserve any relationship-specific overrides
|
|
354
|
+
StartingPayloadValidationMode: subAgentSpec.SubAgent.StartingPayloadValidationMode || fullSubAgentSpec.StartingPayloadValidationMode
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
(0, core_1.LogError)(`Failed to load sub-agent ${subAgentSpec.SubAgent.ID}: ${error instanceof Error ? error.message : String(error)}`);
|
|
359
|
+
// Continue with partial data rather than failing completely
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
248
363
|
}
|
|
249
364
|
this._isLoaded = true;
|
|
250
365
|
this._isDirty = false;
|
|
@@ -260,14 +375,20 @@ class AgentSpecSync {
|
|
|
260
375
|
* @param actions - Array of agent action entities
|
|
261
376
|
* @param childAgents - Array of child agent entities (ParentID-based)
|
|
262
377
|
* @param relatedAgents - Array of related agent relationship entities
|
|
378
|
+
* @param agentPrompts - Array of agent prompt junction entities
|
|
379
|
+
* @param fullPrompts - Array of full AI Prompt entities with PromptText, PromptRole, PromptPosition
|
|
380
|
+
* @param steps - Array of agent step entities (for Flow agents)
|
|
381
|
+
* @param paths - Array of step path entities (for Flow agents)
|
|
263
382
|
* @returns Fully populated AgentSpec object
|
|
264
383
|
*/
|
|
265
|
-
mapEntitiesToRawSpec(agent, actions, childAgents, relatedAgents) {
|
|
384
|
+
mapEntitiesToRawSpec(agent, actions, childAgents, relatedAgents, agentPrompts, fullPrompts, steps, paths) {
|
|
266
385
|
// Map all agent fields to spec
|
|
267
386
|
const spec = {
|
|
268
387
|
ID: agent.ID,
|
|
269
388
|
Name: agent.Name || '',
|
|
270
389
|
Description: agent.Description || undefined,
|
|
390
|
+
TypeID: agent.TypeID || undefined,
|
|
391
|
+
Status: agent.Status || undefined,
|
|
271
392
|
IconClass: agent.IconClass || undefined,
|
|
272
393
|
LogoURL: agent.LogoURL || undefined,
|
|
273
394
|
ParentID: agent.ParentID || undefined,
|
|
@@ -299,13 +420,22 @@ class AgentSpecSync {
|
|
|
299
420
|
DefaultArtifactTypeID: agent.DefaultArtifactTypeID || undefined,
|
|
300
421
|
OwnerUserID: agent.OwnerUserID || undefined,
|
|
301
422
|
InvocationMode: agent.InvocationMode,
|
|
423
|
+
// Requirements and design documentation
|
|
424
|
+
FunctionalRequirements: agent.FunctionalRequirements || null,
|
|
425
|
+
TechnicalDesign: agent.TechnicalDesign || null,
|
|
302
426
|
// Map actions
|
|
303
427
|
Actions: actions.map(action => this.mapActionEntityToSpec(action)),
|
|
304
428
|
// Map sub-agents (both child and related)
|
|
305
429
|
SubAgents: [
|
|
306
430
|
...childAgents.map(child => this.mapChildAgentToSpec(child)),
|
|
307
431
|
...relatedAgents.map(rel => this.mapRelatedAgentToSpec(rel))
|
|
308
|
-
]
|
|
432
|
+
],
|
|
433
|
+
// Map prompts (agent-level prompts for Loop agents)
|
|
434
|
+
Prompts: agentPrompts.map(agentPrompt => this.mapPromptEntityToSpec(agentPrompt, fullPrompts)),
|
|
435
|
+
// Map steps (for Flow agents)
|
|
436
|
+
Steps: steps.map(step => this.mapStepEntityToSpec(step)),
|
|
437
|
+
// Map paths (for Flow agents)
|
|
438
|
+
Paths: paths.map(path => this.mapPathEntityToSpec(path))
|
|
309
439
|
};
|
|
310
440
|
return spec;
|
|
311
441
|
}
|
|
@@ -367,6 +497,71 @@ class AgentSpecSync {
|
|
|
367
497
|
SubAgentContextPaths: this.parseJsonField(relationship.SubAgentContextPaths)
|
|
368
498
|
};
|
|
369
499
|
}
|
|
500
|
+
/**
|
|
501
|
+
* Map AIAgentPromptEntity junction to AgentPromptSpec format.
|
|
502
|
+
*
|
|
503
|
+
* @private
|
|
504
|
+
* @param agentPrompt - The agent prompt junction entity (has PromptID, ExecutionOrder)
|
|
505
|
+
* @param fullPrompts - Array of full AI Prompt entities
|
|
506
|
+
* @returns Mapped prompt spec
|
|
507
|
+
*/
|
|
508
|
+
mapPromptEntityToSpec(agentPrompt, fullPrompts) {
|
|
509
|
+
// Find the full prompt data by matching PromptID
|
|
510
|
+
const fullPrompt = fullPrompts.find((p) => p.ID === agentPrompt.PromptID);
|
|
511
|
+
if (!fullPrompt) {
|
|
512
|
+
// Fallback if prompt not found
|
|
513
|
+
return {
|
|
514
|
+
PromptID: agentPrompt.PromptID || '',
|
|
515
|
+
PromptText: '',
|
|
516
|
+
PromptRole: 'System',
|
|
517
|
+
PromptPosition: 'First'
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
PromptID: fullPrompt.ID || '',
|
|
522
|
+
PromptText: fullPrompt.TemplateText || '',
|
|
523
|
+
PromptRole: fullPrompt.PromptRole || 'System',
|
|
524
|
+
PromptPosition: fullPrompt.PromptPosition || 'First'
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Map AIAgentStepEntity to AgentStep format.
|
|
529
|
+
*
|
|
530
|
+
* @private
|
|
531
|
+
* @param step - The agent step entity
|
|
532
|
+
* @returns Mapped step spec
|
|
533
|
+
*/
|
|
534
|
+
mapStepEntityToSpec(step) {
|
|
535
|
+
return {
|
|
536
|
+
ID: step.ID,
|
|
537
|
+
Name: step.Name,
|
|
538
|
+
Description: step.Description || undefined,
|
|
539
|
+
StepType: step.StepType,
|
|
540
|
+
StartingStep: step.StartingStep,
|
|
541
|
+
ActionID: step.ActionID || undefined,
|
|
542
|
+
SubAgentID: step.SubAgentID || undefined,
|
|
543
|
+
PromptID: step.PromptID || undefined,
|
|
544
|
+
ActionInputMapping: this.parseJsonField(step.ActionInputMapping),
|
|
545
|
+
ActionOutputMapping: this.parseJsonField(step.ActionOutputMapping)
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Map AIAgentStepPathEntity to AgentStepPath format.
|
|
550
|
+
*
|
|
551
|
+
* @private
|
|
552
|
+
* @param path - The agent step path entity
|
|
553
|
+
* @returns Mapped path spec
|
|
554
|
+
*/
|
|
555
|
+
mapPathEntityToSpec(path) {
|
|
556
|
+
return {
|
|
557
|
+
ID: path.ID,
|
|
558
|
+
OriginStepID: path.OriginStepID,
|
|
559
|
+
DestinationStepID: path.DestinationStepID,
|
|
560
|
+
Condition: path.Condition || undefined,
|
|
561
|
+
Description: path.Description || undefined,
|
|
562
|
+
Priority: path.Priority
|
|
563
|
+
};
|
|
564
|
+
}
|
|
370
565
|
// ===== SAVING METHODS =====
|
|
371
566
|
/**
|
|
372
567
|
* Save the current spec to the database.
|
|
@@ -378,7 +573,7 @@ class AgentSpecSync {
|
|
|
378
573
|
* database schema are executed, and any failures will prevent the save.
|
|
379
574
|
*
|
|
380
575
|
* @param validate - Whether to validate before saving (default: true)
|
|
381
|
-
* @returns Promise resolving to
|
|
576
|
+
* @returns Promise resolving to result with agent ID, success flag, and all mutations performed
|
|
382
577
|
* @throws {Error} If validation fails or save operation fails
|
|
383
578
|
*
|
|
384
579
|
* @example
|
|
@@ -388,26 +583,51 @@ class AgentSpecSync {
|
|
|
388
583
|
* InvocationMode: 'Any'
|
|
389
584
|
* }, contextUser);
|
|
390
585
|
*
|
|
391
|
-
* const
|
|
392
|
-
* console.log('Saved with ID:', agentId);
|
|
586
|
+
* const result = await spec.SaveToDatabase();
|
|
587
|
+
* console.log('Saved with ID:', result.agentId);
|
|
588
|
+
* console.log('Mutations:', result.mutations.length);
|
|
393
589
|
* ```
|
|
394
590
|
*/
|
|
395
591
|
async SaveToDatabase(validate = true) {
|
|
592
|
+
// Clear previous mutations
|
|
593
|
+
this.clearMutations();
|
|
396
594
|
if (!this._isDirty && this._isLoaded) {
|
|
397
595
|
// No changes to save
|
|
398
|
-
return
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
596
|
+
return {
|
|
597
|
+
agentId: this.spec.ID,
|
|
598
|
+
success: true,
|
|
599
|
+
mutations: []
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
try {
|
|
603
|
+
// Step 1: Save main agent entity
|
|
604
|
+
const agentId = await this.saveAgentEntity(validate);
|
|
605
|
+
// Step 2: Save actions
|
|
606
|
+
await this.saveActions(agentId);
|
|
607
|
+
// Step 3: Save sub-agents (both child and related)
|
|
608
|
+
await this.saveSubAgents(agentId);
|
|
609
|
+
// Step 4: Save prompts
|
|
610
|
+
await this.savePrompts(agentId);
|
|
611
|
+
// Step 5: Save steps (Flow agents only)
|
|
612
|
+
await this.saveSteps(agentId);
|
|
613
|
+
// Step 6: Save step paths (Flow agents only)
|
|
614
|
+
await this.saveStepPaths(agentId);
|
|
615
|
+
this._isDirty = false;
|
|
616
|
+
this._isLoaded = true;
|
|
617
|
+
return {
|
|
618
|
+
agentId,
|
|
619
|
+
success: true,
|
|
620
|
+
mutations: this.getMutations()
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
catch (error) {
|
|
624
|
+
// Return failure with whatever mutations were completed before error
|
|
625
|
+
return {
|
|
626
|
+
agentId: this.spec.ID || '',
|
|
627
|
+
success: false,
|
|
628
|
+
mutations: this.getMutations()
|
|
629
|
+
};
|
|
630
|
+
}
|
|
411
631
|
}
|
|
412
632
|
/**
|
|
413
633
|
* Save the main AIAgent entity.
|
|
@@ -420,6 +640,8 @@ class AgentSpecSync {
|
|
|
420
640
|
async saveAgentEntity(validate) {
|
|
421
641
|
const md = new core_1.Metadata();
|
|
422
642
|
const agentEntity = await md.GetEntityObject('AI Agents', this._contextUser);
|
|
643
|
+
// Track if this is an update or create
|
|
644
|
+
const isUpdate = !!this.spec.ID;
|
|
423
645
|
// If ID exists, load existing record
|
|
424
646
|
if (this.spec.ID) {
|
|
425
647
|
const loaded = await agentEntity.Load(this.spec.ID);
|
|
@@ -435,6 +657,17 @@ class AgentSpecSync {
|
|
|
435
657
|
agentEntity.ParentID = this.spec.ParentID || null;
|
|
436
658
|
agentEntity.DriverClass = this.spec.DriverClass || null;
|
|
437
659
|
agentEntity.ModelSelectionMode = this.spec.ModelSelectionMode || 'Agent Type';
|
|
660
|
+
// Handle TypeID - supports lookup references or direct GUID
|
|
661
|
+
if (this.spec.TypeID) {
|
|
662
|
+
agentEntity.TypeID = this.spec.TypeID;
|
|
663
|
+
}
|
|
664
|
+
// Handle Status - defaults to Active if not specified
|
|
665
|
+
if (this.spec.Status) {
|
|
666
|
+
agentEntity.Status = this.spec.Status;
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
agentEntity.Status = 'Active';
|
|
670
|
+
}
|
|
438
671
|
// Serialize JSON fields
|
|
439
672
|
agentEntity.PayloadDownstreamPaths = JSON.stringify(this.spec.PayloadDownstreamPaths || ['*']);
|
|
440
673
|
agentEntity.PayloadUpstreamPaths = JSON.stringify(this.spec.PayloadUpstreamPaths || ['*']);
|
|
@@ -467,6 +700,9 @@ class AgentSpecSync {
|
|
|
467
700
|
agentEntity.OwnerUserID = this.spec.OwnerUserID;
|
|
468
701
|
}
|
|
469
702
|
agentEntity.InvocationMode = this.spec.InvocationMode || 'Any';
|
|
703
|
+
// Requirements and design documentation
|
|
704
|
+
agentEntity.FunctionalRequirements = this.spec.FunctionalRequirements || null;
|
|
705
|
+
agentEntity.TechnicalDesign = this.spec.TechnicalDesign || null;
|
|
470
706
|
// Validate if requested
|
|
471
707
|
if (validate) {
|
|
472
708
|
const validation = agentEntity.Validate();
|
|
@@ -482,6 +718,8 @@ class AgentSpecSync {
|
|
|
482
718
|
}
|
|
483
719
|
// Update spec with saved ID
|
|
484
720
|
this.spec.ID = agentEntity.ID;
|
|
721
|
+
// Track the mutation
|
|
722
|
+
this.trackMutation('AI Agents', isUpdate ? 'Update' : 'Create', agentEntity.ID, `${isUpdate ? 'Updated' : 'Created'} agent: ${this.spec.Name}`);
|
|
485
723
|
return agentEntity.ID;
|
|
486
724
|
}
|
|
487
725
|
/**
|
|
@@ -502,6 +740,8 @@ class AgentSpecSync {
|
|
|
502
740
|
const md = new core_1.Metadata();
|
|
503
741
|
for (const actionSpec of this.spec.Actions) {
|
|
504
742
|
const actionEntity = await md.GetEntityObject('AI Agent Actions', this._contextUser);
|
|
743
|
+
// Track if this is an update or create
|
|
744
|
+
const isUpdate = !!actionSpec.AgentActionID;
|
|
505
745
|
// Load existing if ID provided
|
|
506
746
|
if (actionSpec.AgentActionID) {
|
|
507
747
|
await actionEntity.Load(actionSpec.AgentActionID);
|
|
@@ -522,6 +762,8 @@ class AgentSpecSync {
|
|
|
522
762
|
}
|
|
523
763
|
// Update spec with saved ID
|
|
524
764
|
actionSpec.AgentActionID = actionEntity.ID;
|
|
765
|
+
// Track the mutation
|
|
766
|
+
this.trackMutation('AI Agent Actions', isUpdate ? 'Update' : 'Create', actionEntity.ID, `${isUpdate ? 'Updated' : 'Created'} action junction for action ${actionSpec.ActionID}`);
|
|
525
767
|
}
|
|
526
768
|
}
|
|
527
769
|
/**
|
|
@@ -576,32 +818,25 @@ class AgentSpecSync {
|
|
|
576
818
|
// Recursively create the sub-agent using AgentSpecSync
|
|
577
819
|
const childSync = new AgentSpecSync(childSpec, this._contextUser);
|
|
578
820
|
childSync.markDirty();
|
|
579
|
-
const
|
|
821
|
+
const childResult = await childSync.SaveToDatabase();
|
|
580
822
|
// Update the SubAgentSpec with the created ID so parent can reference it
|
|
581
|
-
SubAgentSpec.SubAgent.ID =
|
|
582
|
-
console.log(`✅ saveChildSubAgent: Created child sub-agent with ID: ${
|
|
823
|
+
SubAgentSpec.SubAgent.ID = childResult.agentId;
|
|
824
|
+
console.log(`✅ saveChildSubAgent: Created child sub-agent with ID: ${childResult.agentId}`);
|
|
583
825
|
}
|
|
584
826
|
else {
|
|
585
|
-
// SubAgent already exists -
|
|
827
|
+
// SubAgent already exists - update it recursively to capture all field changes
|
|
586
828
|
console.log(`🔗 saveChildSubAgent: Updating existing child sub-agent "${SubAgentSpec.SubAgent.ID}"...`);
|
|
587
|
-
|
|
588
|
-
const
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
//
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
if (!saved) {
|
|
599
|
-
throw new Error(`Failed to update ParentID for child agent ${SubAgentSpec.SubAgent.ID}`);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
console.log(`✅ saveChildSubAgent: ParentID already correct`);
|
|
604
|
-
}
|
|
829
|
+
// Set ParentID in the sub-agent spec
|
|
830
|
+
const childSpec = {
|
|
831
|
+
...SubAgentSpec.SubAgent,
|
|
832
|
+
ParentID: parentId
|
|
833
|
+
};
|
|
834
|
+
// Recursively update the sub-agent using AgentSpecSync
|
|
835
|
+
// This ensures all fields including FunctionalRequirements and TechnicalDesign are updated
|
|
836
|
+
const childSync = new AgentSpecSync(childSpec, this._contextUser);
|
|
837
|
+
childSync.markDirty();
|
|
838
|
+
await childSync.SaveToDatabase();
|
|
839
|
+
console.log(`✅ saveChildSubAgent: Updated existing child sub-agent`);
|
|
605
840
|
}
|
|
606
841
|
}
|
|
607
842
|
/**
|
|
@@ -619,7 +854,8 @@ class AgentSpecSync {
|
|
|
619
854
|
const md = new core_1.Metadata();
|
|
620
855
|
const relationshipEntity = await md.GetEntityObject('MJ: AI Agent Relationships', this._contextUser);
|
|
621
856
|
// Load existing if ID provided
|
|
622
|
-
|
|
857
|
+
const isUpdate = !!SubAgentSpec.AgentRelationshipID;
|
|
858
|
+
if (isUpdate && SubAgentSpec.AgentRelationshipID) {
|
|
623
859
|
await relationshipEntity.Load(SubAgentSpec.AgentRelationshipID);
|
|
624
860
|
}
|
|
625
861
|
// Map fields
|
|
@@ -649,6 +885,8 @@ class AgentSpecSync {
|
|
|
649
885
|
if (!saved) {
|
|
650
886
|
throw new Error(`Failed to save relationship for sub-agent ${SubAgentSpec.SubAgent.ID}`);
|
|
651
887
|
}
|
|
888
|
+
// Track mutation
|
|
889
|
+
this.trackMutation('AI Agent Relationships', isUpdate ? 'Update' : 'Create', relationshipEntity.ID, `${isUpdate ? 'Updated' : 'Created'} agent relationship for sub-agent ${SubAgentSpec.SubAgent.ID}`);
|
|
652
890
|
// Update spec with saved ID
|
|
653
891
|
SubAgentSpec.AgentRelationshipID = relationshipEntity.ID;
|
|
654
892
|
}
|
|
@@ -671,11 +909,25 @@ class AgentSpecSync {
|
|
|
671
909
|
}
|
|
672
910
|
console.log(`💬 savePrompts: Processing ${this.spec.Prompts.length} prompt(s)...`);
|
|
673
911
|
const md = new core_1.Metadata();
|
|
912
|
+
const rv = new core_1.RunView();
|
|
913
|
+
// Step 1: Create or update AIPrompt records
|
|
674
914
|
for (let i = 0; i < this.spec.Prompts.length; i++) {
|
|
675
915
|
const promptSpec = this.spec.Prompts[i];
|
|
676
|
-
//
|
|
677
|
-
|
|
678
|
-
|
|
916
|
+
// Check if this is an update (has PromptID) or create (no PromptID)
|
|
917
|
+
let promptEntity = await md.GetEntityObject('AI Prompts', this._contextUser);
|
|
918
|
+
let isUpdate = false;
|
|
919
|
+
if (promptSpec.PromptID && promptSpec.PromptID !== '') {
|
|
920
|
+
// Load existing prompt for update
|
|
921
|
+
const loaded = await promptEntity.Load(promptSpec.PromptID);
|
|
922
|
+
if (loaded) {
|
|
923
|
+
isUpdate = true;
|
|
924
|
+
console.log(`💬 savePrompts: Updating existing prompt ID: ${promptSpec.PromptID}`);
|
|
925
|
+
}
|
|
926
|
+
else {
|
|
927
|
+
console.warn(`💬 savePrompts: PromptID specified but not found, creating new prompt`);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
// Set all required fields (both create and update)
|
|
679
931
|
promptEntity.Name = `${this.spec.Name} - Prompt ${i + 1}`;
|
|
680
932
|
promptEntity.Description = `Agent prompt ${i + 1} for ${this.spec.Name}`;
|
|
681
933
|
promptEntity.TypeID = 'a6da423e-f36b-1410-8dac-00021f8b792e'; // Chat type
|
|
@@ -705,21 +957,208 @@ class AgentSpecSync {
|
|
|
705
957
|
if (!saved) {
|
|
706
958
|
throw new Error(`Failed to save prompt ${i + 1} for agent ${this.spec.Name}`);
|
|
707
959
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
960
|
+
// Track mutation
|
|
961
|
+
this.trackMutation('AI Prompts', isUpdate ? 'Update' : 'Create', promptEntity.ID, `${isUpdate ? 'Updated' : 'Created'} prompt: ${promptEntity.Name}`);
|
|
962
|
+
// Update the spec with the saved/updated ID
|
|
963
|
+
promptSpec.PromptID = promptEntity.ID;
|
|
964
|
+
console.log(`✅ savePrompts: ${isUpdate ? 'Updated' : 'Created'} AIPrompt with ID: ${promptEntity.ID}`);
|
|
965
|
+
// Step 2: Create or update AIAgentPrompt junction
|
|
966
|
+
// Query for existing junction by AgentID + PromptID
|
|
967
|
+
const existingJunctionResult = await rv.RunView({
|
|
968
|
+
EntityName: 'MJ: AI Agent Prompts',
|
|
969
|
+
ExtraFilter: `AgentID='${agentId}' AND PromptID='${promptEntity.ID}'`,
|
|
970
|
+
ResultType: 'entity_object'
|
|
971
|
+
}, this._contextUser);
|
|
972
|
+
let agentPromptEntity;
|
|
973
|
+
let isJunctionUpdate = false;
|
|
974
|
+
if (existingJunctionResult.Success && existingJunctionResult.Results && existingJunctionResult.Results.length > 0) {
|
|
975
|
+
// Junction exists - load it for update
|
|
976
|
+
agentPromptEntity = existingJunctionResult.Results[0];
|
|
977
|
+
isJunctionUpdate = true;
|
|
978
|
+
console.log(`💬 savePrompts: Updating existing junction for prompt ${i + 1}`);
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
// Junction doesn't exist - create new one
|
|
982
|
+
agentPromptEntity = await md.GetEntityObject('MJ: AI Agent Prompts', this._contextUser);
|
|
983
|
+
agentPromptEntity.AgentID = agentId;
|
|
984
|
+
agentPromptEntity.PromptID = promptEntity.ID;
|
|
985
|
+
console.log(`💬 savePrompts: Creating new junction for prompt ${i + 1}`);
|
|
986
|
+
}
|
|
987
|
+
// Set/update common fields (ExecutionOrder might change)
|
|
713
988
|
agentPromptEntity.ExecutionOrder = i;
|
|
714
989
|
agentPromptEntity.Status = 'Active';
|
|
715
990
|
const junctionSaved = await agentPromptEntity.Save();
|
|
716
991
|
if (!junctionSaved) {
|
|
717
992
|
throw new Error(`Failed to save agent-prompt junction for prompt ${i + 1}`);
|
|
718
993
|
}
|
|
719
|
-
|
|
994
|
+
// Track mutation
|
|
995
|
+
this.trackMutation('AI Agent Prompts', isJunctionUpdate ? 'Update' : 'Create', agentPromptEntity.ID, `${isJunctionUpdate ? 'Updated' : 'Created'} agent-prompt junction for prompt ${promptEntity.ID}`);
|
|
996
|
+
console.log(`✅ savePrompts: ${isJunctionUpdate ? 'Updated' : 'Created'} AIAgentPrompt junction with ID: ${agentPromptEntity.ID}`);
|
|
720
997
|
}
|
|
721
998
|
console.log(`✅ savePrompts: Successfully saved all ${this.spec.Prompts.length} prompt(s)`);
|
|
722
999
|
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Save all steps for this agent (Flow agents only).
|
|
1002
|
+
*
|
|
1003
|
+
* Creates AIAgentStep records for each step in the spec. Steps define the nodes
|
|
1004
|
+
* in a Flow agent's execution graph.
|
|
1005
|
+
*
|
|
1006
|
+
* @private
|
|
1007
|
+
* @param agentId - The parent agent ID
|
|
1008
|
+
* @throws {Error} If any step save fails
|
|
1009
|
+
*/
|
|
1010
|
+
async saveSteps(agentId) {
|
|
1011
|
+
console.log(`🔷 saveSteps: Called with agentId=${agentId}, Steps=${this.spec.Steps ? this.spec.Steps.length : 'undefined'}`);
|
|
1012
|
+
if (!this.spec.Steps || this.spec.Steps.length === 0) {
|
|
1013
|
+
console.log('🔷 saveSteps: No steps to save, returning early');
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
console.log(`🔷 saveSteps: Processing ${this.spec.Steps.length} step(s)...`);
|
|
1017
|
+
const md = new core_1.Metadata();
|
|
1018
|
+
for (const stepSpec of this.spec.Steps) {
|
|
1019
|
+
const stepEntity = await md.GetEntityObject('MJ: AI Agent Steps', this._contextUser);
|
|
1020
|
+
// Load existing if ID provided
|
|
1021
|
+
const isUpdate = !!(stepSpec.ID && stepSpec.ID !== '');
|
|
1022
|
+
if (isUpdate) {
|
|
1023
|
+
await stepEntity.Load(stepSpec.ID);
|
|
1024
|
+
}
|
|
1025
|
+
// Map fields
|
|
1026
|
+
stepEntity.AgentID = agentId;
|
|
1027
|
+
stepEntity.Name = stepSpec.Name;
|
|
1028
|
+
stepEntity.Description = stepSpec.Description || null;
|
|
1029
|
+
stepEntity.StepType = stepSpec.StepType;
|
|
1030
|
+
stepEntity.StartingStep = stepSpec.StartingStep;
|
|
1031
|
+
stepEntity.ActionID = stepSpec.ActionID || null;
|
|
1032
|
+
stepEntity.SubAgentID = stepSpec.SubAgentID || null;
|
|
1033
|
+
stepEntity.Status = 'Active'; // Default to Active
|
|
1034
|
+
// Handle inline prompt creation for Prompt-type steps
|
|
1035
|
+
// If StepType is Prompt and PromptID is empty, create a new AIPrompt record
|
|
1036
|
+
if (stepSpec.StepType === 'Prompt' && (!stepSpec.PromptID || stepSpec.PromptID === '')) {
|
|
1037
|
+
if (stepSpec.PromptText) {
|
|
1038
|
+
console.log(`🔷 saveSteps: Creating inline prompt for step "${stepSpec.Name}"`);
|
|
1039
|
+
// Create AIPrompt entity (using any type for TemplateText dynamic property)
|
|
1040
|
+
const promptEntity = await md.GetEntityObject('AI Prompts', this._contextUser);
|
|
1041
|
+
// Set prompt fields
|
|
1042
|
+
promptEntity.Name = stepSpec.PromptName || `${stepSpec.Name} Prompt`;
|
|
1043
|
+
promptEntity.Description = stepSpec.PromptDescription || `Prompt for step: ${stepSpec.Name}`;
|
|
1044
|
+
promptEntity.TypeID = 'a6da423e-f36b-1410-8dac-00021f8b792e'; // Chat type
|
|
1045
|
+
promptEntity.Status = 'Active';
|
|
1046
|
+
promptEntity.ResponseFormat = 'JSON';
|
|
1047
|
+
promptEntity.TemplateText = stepSpec.PromptText; // TemplateText is a dynamic property
|
|
1048
|
+
const promptSaved = await promptEntity.Save();
|
|
1049
|
+
if (!promptSaved) {
|
|
1050
|
+
throw new Error(`Failed to save inline prompt for step "${stepSpec.Name}"`);
|
|
1051
|
+
}
|
|
1052
|
+
// Track mutation
|
|
1053
|
+
this.trackMutation('AI Prompts', 'Create', promptEntity.ID, `Created inline prompt: ${promptEntity.Name}`);
|
|
1054
|
+
console.log(`✅ saveSteps: Created inline AIPrompt with ID: ${promptEntity.ID}`);
|
|
1055
|
+
// Link the created prompt to this step
|
|
1056
|
+
stepEntity.PromptID = promptEntity.ID;
|
|
1057
|
+
stepSpec.PromptID = promptEntity.ID; // Update spec too
|
|
1058
|
+
}
|
|
1059
|
+
else {
|
|
1060
|
+
console.warn(`⚠️ saveSteps: Step "${stepSpec.Name}" is Prompt type with empty PromptID but no PromptText provided`);
|
|
1061
|
+
stepEntity.PromptID = null;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
else {
|
|
1065
|
+
stepEntity.PromptID = stepSpec.PromptID || null;
|
|
1066
|
+
}
|
|
1067
|
+
// Map Action I/O mappings for Flow agent action steps
|
|
1068
|
+
// Handle ActionInputMapping - convert object to JSON string if needed
|
|
1069
|
+
if (stepSpec.ActionInputMapping) {
|
|
1070
|
+
stepEntity.ActionInputMapping = typeof stepSpec.ActionInputMapping === 'string'
|
|
1071
|
+
? stepSpec.ActionInputMapping
|
|
1072
|
+
: JSON.stringify(stepSpec.ActionInputMapping);
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
stepEntity.ActionInputMapping = null;
|
|
1076
|
+
}
|
|
1077
|
+
// Handle ActionOutputMapping - convert object to JSON string if needed
|
|
1078
|
+
if (stepSpec.ActionOutputMapping) {
|
|
1079
|
+
stepEntity.ActionOutputMapping = typeof stepSpec.ActionOutputMapping === 'string'
|
|
1080
|
+
? stepSpec.ActionOutputMapping
|
|
1081
|
+
: JSON.stringify(stepSpec.ActionOutputMapping);
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
stepEntity.ActionOutputMapping = null;
|
|
1085
|
+
}
|
|
1086
|
+
const saved = await stepEntity.Save();
|
|
1087
|
+
if (!saved) {
|
|
1088
|
+
throw new Error(`Failed to save step "${stepSpec.Name}" for agent ${this.spec.Name}`);
|
|
1089
|
+
}
|
|
1090
|
+
// Track mutation
|
|
1091
|
+
this.trackMutation('AI Agent Steps', isUpdate ? 'Update' : 'Create', stepEntity.ID, `${isUpdate ? 'Updated' : 'Created'} step: ${stepSpec.Name}`);
|
|
1092
|
+
// Update the spec with the saved ID so paths can reference it
|
|
1093
|
+
stepSpec.ID = stepEntity.ID;
|
|
1094
|
+
console.log(`✅ saveSteps: Created AIAgentStep with ID: ${stepEntity.ID}`);
|
|
1095
|
+
}
|
|
1096
|
+
console.log(`✅ saveSteps: Successfully saved all ${this.spec.Steps.length} step(s)`);
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Save all step paths for this agent (Flow agents only).
|
|
1100
|
+
*
|
|
1101
|
+
* Creates AIAgentStepPath records that define the edges in a Flow agent's
|
|
1102
|
+
* execution graph, including conditional branching logic.
|
|
1103
|
+
*
|
|
1104
|
+
* @private
|
|
1105
|
+
* @param agentId - The parent agent ID
|
|
1106
|
+
* @throws {Error} If any path save fails
|
|
1107
|
+
*/
|
|
1108
|
+
async saveStepPaths(agentId) {
|
|
1109
|
+
console.log(`🔶 saveStepPaths: Called with agentId=${agentId}, Paths=${this.spec.Paths ? this.spec.Paths.length : 'undefined'}`);
|
|
1110
|
+
if (!this.spec.Paths || this.spec.Paths.length === 0) {
|
|
1111
|
+
console.log('🔶 saveStepPaths: No paths to save, returning early');
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
console.log(`🔶 saveStepPaths: Processing ${this.spec.Paths.length} path(s)...`);
|
|
1115
|
+
const md = new core_1.Metadata();
|
|
1116
|
+
// Create a map of step names to IDs for easy lookup
|
|
1117
|
+
const stepNameToId = new Map();
|
|
1118
|
+
if (this.spec.Steps) {
|
|
1119
|
+
for (const step of this.spec.Steps) {
|
|
1120
|
+
if (step.ID) {
|
|
1121
|
+
stepNameToId.set(step.Name, step.ID);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
for (const pathSpec of this.spec.Paths) {
|
|
1126
|
+
const pathEntity = await md.GetEntityObject('MJ: AI Agent Step Paths', this._contextUser);
|
|
1127
|
+
// Load existing if ID provided
|
|
1128
|
+
const isUpdate = !!(pathSpec.ID && pathSpec.ID !== '');
|
|
1129
|
+
if (isUpdate) {
|
|
1130
|
+
await pathEntity.Load(pathSpec.ID);
|
|
1131
|
+
}
|
|
1132
|
+
// Resolve step IDs from step names
|
|
1133
|
+
// OriginStepID and DestinationStepID can be either step IDs or step names
|
|
1134
|
+
// If they're names, look them up in our map
|
|
1135
|
+
let originStepId = pathSpec.OriginStepID;
|
|
1136
|
+
let destinationStepId = pathSpec.DestinationStepID;
|
|
1137
|
+
// Try to resolve as step names first
|
|
1138
|
+
if (stepNameToId.has(pathSpec.OriginStepID)) {
|
|
1139
|
+
originStepId = stepNameToId.get(pathSpec.OriginStepID);
|
|
1140
|
+
}
|
|
1141
|
+
if (stepNameToId.has(pathSpec.DestinationStepID)) {
|
|
1142
|
+
destinationStepId = stepNameToId.get(pathSpec.DestinationStepID);
|
|
1143
|
+
}
|
|
1144
|
+
// Map fields
|
|
1145
|
+
pathEntity.OriginStepID = originStepId;
|
|
1146
|
+
pathEntity.DestinationStepID = destinationStepId;
|
|
1147
|
+
pathEntity.Condition = pathSpec.Condition || null;
|
|
1148
|
+
pathEntity.Description = pathSpec.Description || null;
|
|
1149
|
+
pathEntity.Priority = pathSpec.Priority;
|
|
1150
|
+
const saved = await pathEntity.Save();
|
|
1151
|
+
if (!saved) {
|
|
1152
|
+
throw new Error(`Failed to save path from "${pathSpec.OriginStepID}" to "${pathSpec.DestinationStepID}"`);
|
|
1153
|
+
}
|
|
1154
|
+
// Track mutation
|
|
1155
|
+
this.trackMutation('AI Agent Step Paths', isUpdate ? 'Update' : 'Create', pathEntity.ID, `${isUpdate ? 'Updated' : 'Created'} path from "${pathSpec.OriginStepID}" to "${pathSpec.DestinationStepID}"`);
|
|
1156
|
+
// Update the spec with the saved ID
|
|
1157
|
+
pathSpec.ID = pathEntity.ID;
|
|
1158
|
+
console.log(`✅ saveStepPaths: Created AIAgentStepPath with ID: ${pathEntity.ID}`);
|
|
1159
|
+
}
|
|
1160
|
+
console.log(`✅ saveStepPaths: Successfully saved all ${this.spec.Paths.length} path(s)`);
|
|
1161
|
+
}
|
|
723
1162
|
// ===== UTILITY METHODS =====
|
|
724
1163
|
/**
|
|
725
1164
|
* Parse a JSON string field, returning undefined if null/empty.
|
|
@@ -757,6 +1196,9 @@ class AgentSpecSync {
|
|
|
757
1196
|
ID: partial.ID || '',
|
|
758
1197
|
Name: partial.Name || '',
|
|
759
1198
|
Description: partial.Description,
|
|
1199
|
+
// TypeID and Status are extended fields (not in base AgentSpec interface)
|
|
1200
|
+
TypeID: partial.TypeID,
|
|
1201
|
+
Status: partial.Status || 'Active',
|
|
760
1202
|
IconClass: partial.IconClass,
|
|
761
1203
|
LogoURL: partial.LogoURL,
|
|
762
1204
|
ParentID: partial.ParentID,
|
|
@@ -783,9 +1225,14 @@ class AgentSpecSync {
|
|
|
783
1225
|
DefaultArtifactTypeID: partial.DefaultArtifactTypeID,
|
|
784
1226
|
OwnerUserID: partial.OwnerUserID,
|
|
785
1227
|
InvocationMode: partial.InvocationMode || 'Any',
|
|
1228
|
+
FunctionalRequirements: partial.FunctionalRequirements,
|
|
1229
|
+
TechnicalDesign: partial.TechnicalDesign,
|
|
786
1230
|
Actions: partial.Actions || [],
|
|
787
1231
|
SubAgents: partial.SubAgents || [],
|
|
788
|
-
Prompts: partial.Prompts || []
|
|
1232
|
+
Prompts: partial.Prompts || [],
|
|
1233
|
+
// Flow agent fields - critical for Flow agent support
|
|
1234
|
+
Steps: partial.Steps || [],
|
|
1235
|
+
Paths: partial.Paths || []
|
|
789
1236
|
};
|
|
790
1237
|
}
|
|
791
1238
|
/**
|