@memberjunction/ai-agents 2.68.0 → 2.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -0
- package/dist/PayloadManager.d.ts +4 -0
- package/dist/PayloadManager.d.ts.map +1 -1
- package/dist/PayloadManager.js +73 -0
- package/dist/PayloadManager.js.map +1 -1
- package/dist/agent-types/loop-agent-type.d.ts +1 -0
- package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-type.js +8 -0
- package/dist/agent-types/loop-agent-type.js.map +1 -1
- package/dist/base-agent.d.ts +28 -9
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +400 -23
- package/dist/base-agent.js.map +1 -1
- package/package.json +10 -10
package/dist/base-agent.js
CHANGED
|
@@ -38,12 +38,18 @@ class BaseAgent {
|
|
|
38
38
|
constructor() {
|
|
39
39
|
this._promptRunner = new ai_prompts_1.AIPromptRunner();
|
|
40
40
|
this._metadata = new core_1.Metadata();
|
|
41
|
+
this._executionCounts = new Map();
|
|
42
|
+
this._generalValidationRetryCount = 0;
|
|
41
43
|
this._agentRun = null;
|
|
42
44
|
this._agentHierarchy = [];
|
|
43
45
|
this._depth = 0;
|
|
44
46
|
this._allProgressSteps = [];
|
|
45
47
|
this._subAgentRuns = [];
|
|
46
48
|
this._payloadManager = new PayloadManager_1.PayloadManager();
|
|
49
|
+
this._validationRetryCount = 0;
|
|
50
|
+
}
|
|
51
|
+
get ValidationRetryCount() {
|
|
52
|
+
return this._validationRetryCount;
|
|
47
53
|
}
|
|
48
54
|
logStatus(message, verboseOnly = false, params) {
|
|
49
55
|
if (verboseOnly) {
|
|
@@ -128,6 +134,8 @@ class BaseAgent {
|
|
|
128
134
|
message: this.formatHierarchicalMessage(`Initializing ${params.agent.Name} agent and preparing execution environment`)
|
|
129
135
|
});
|
|
130
136
|
await this.initializeAgentRun(wrappedParams);
|
|
137
|
+
this._validationRetryCount = 0;
|
|
138
|
+
this._generalValidationRetryCount = 0;
|
|
131
139
|
await this.initializeEngines(params.contextUser);
|
|
132
140
|
if (params.cancellationToken?.aborted) {
|
|
133
141
|
return await this.createCancelledResult('Cancelled during initialization', params.contextUser);
|
|
@@ -349,20 +357,20 @@ class BaseAgent {
|
|
|
349
357
|
const nextStep = await agentTypeInstance.DetermineNextStep(promptResult, currentPayload);
|
|
350
358
|
return nextStep;
|
|
351
359
|
}
|
|
352
|
-
async validateNextStep(params, nextStep, currentPayload) {
|
|
360
|
+
async validateNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
|
|
353
361
|
switch (nextStep.step) {
|
|
354
362
|
case 'Sub-Agent':
|
|
355
|
-
return this.validateSubAgentNextStep(params, nextStep, currentPayload);
|
|
363
|
+
return this.validateSubAgentNextStep(params, nextStep, currentPayload, agentRun, currentStep);
|
|
356
364
|
case 'Actions':
|
|
357
|
-
return this.validateActionsNextStep(params, nextStep, currentPayload);
|
|
365
|
+
return this.validateActionsNextStep(params, nextStep, currentPayload, agentRun, currentStep);
|
|
358
366
|
case 'Success':
|
|
359
|
-
return this.validateSuccessNextStep(params, nextStep, currentPayload);
|
|
367
|
+
return this.validateSuccessNextStep(params, nextStep, currentPayload, agentRun, currentStep);
|
|
360
368
|
case 'Chat':
|
|
361
|
-
return this.validateChatNextStep(params, nextStep, currentPayload);
|
|
369
|
+
return this.validateChatNextStep(params, nextStep, currentPayload, agentRun, currentStep);
|
|
362
370
|
case 'Retry':
|
|
363
|
-
return this.validateRetryNextStep(params, nextStep, currentPayload);
|
|
371
|
+
return this.validateRetryNextStep(params, nextStep, currentPayload, agentRun, currentStep);
|
|
364
372
|
case 'Failed':
|
|
365
|
-
return this.validateFailedNextStep(params, nextStep, currentPayload);
|
|
373
|
+
return this.validateFailedNextStep(params, nextStep, currentPayload, agentRun, currentStep);
|
|
366
374
|
default:
|
|
367
375
|
this.logError(`Invalid next step '${nextStep.step}' for agent '${params.agent.Name}'`, {
|
|
368
376
|
agent: params.agent,
|
|
@@ -375,23 +383,49 @@ class BaseAgent {
|
|
|
375
383
|
};
|
|
376
384
|
}
|
|
377
385
|
}
|
|
378
|
-
async validateSubAgentNextStep(params, nextStep, currentPayload) {
|
|
386
|
+
async validateSubAgentNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
|
|
379
387
|
const name = nextStep.subAgent?.name;
|
|
380
|
-
const curAgentSubAgents = aiengine_1.AIEngine.Instance.
|
|
381
|
-
|
|
388
|
+
const curAgentSubAgents = aiengine_1.AIEngine.Instance.GetSubAgents(params.agent.ID, 'Active');
|
|
389
|
+
const subAgent = curAgentSubAgents.find(a => a.Name.trim().toLowerCase() === name?.trim().toLowerCase());
|
|
390
|
+
if (!name || !subAgent) {
|
|
382
391
|
this.logError(`Sub-agent '${name}' not found or not active for agent '${params.agent.Name}'`, {
|
|
383
392
|
agent: params.agent,
|
|
384
393
|
category: 'SubAgentExecution'
|
|
385
394
|
});
|
|
395
|
+
if (nextStep.step !== 'Retry') {
|
|
396
|
+
this._generalValidationRetryCount++;
|
|
397
|
+
}
|
|
386
398
|
return {
|
|
387
399
|
step: 'Retry',
|
|
388
400
|
terminate: false,
|
|
389
401
|
errorMessage: `Sub-agent '${name}' not found or not active`
|
|
390
402
|
};
|
|
391
403
|
}
|
|
404
|
+
if (subAgent.MaxExecutionsPerRun != null) {
|
|
405
|
+
const executionCount = await this.getSubAgentExecutionCount(agentRun.ID, subAgent.ID);
|
|
406
|
+
if (executionCount >= subAgent.MaxExecutionsPerRun) {
|
|
407
|
+
this.logError(`Sub-agent '${name}' has reached its maximum execution limit of ${subAgent.MaxExecutionsPerRun}`, {
|
|
408
|
+
agent: params.agent,
|
|
409
|
+
category: 'SubAgentExecution',
|
|
410
|
+
metadata: {
|
|
411
|
+
subAgentName: name,
|
|
412
|
+
executionCount,
|
|
413
|
+
maxExecutions: subAgent.MaxExecutionsPerRun
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
if (nextStep.step !== 'Retry') {
|
|
417
|
+
this._generalValidationRetryCount++;
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
step: 'Retry',
|
|
421
|
+
terminate: false,
|
|
422
|
+
errorMessage: `Sub-agent '${name}' has reached its maximum execution limit of ${subAgent.MaxExecutionsPerRun}`
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
}
|
|
392
426
|
return nextStep;
|
|
393
427
|
}
|
|
394
|
-
async validateActionsNextStep(params, nextStep, currentPayload) {
|
|
428
|
+
async validateActionsNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
|
|
395
429
|
const curAgentActions = aiengine_1.AIEngine.Instance.AgentActions.filter(aa => aa.AgentID === params.agent.ID && aa.Status === 'Active');
|
|
396
430
|
const missingActions = nextStep.actions?.filter(action => !curAgentActions.some(aa => aa.Action.trim().toLowerCase() === action.name.trim().toLowerCase()));
|
|
397
431
|
if (missingActions && missingActions.length > 0) {
|
|
@@ -400,31 +434,312 @@ class BaseAgent {
|
|
|
400
434
|
agent: params.agent,
|
|
401
435
|
category: 'ActionExecution'
|
|
402
436
|
});
|
|
437
|
+
if (nextStep.step !== 'Retry') {
|
|
438
|
+
this._generalValidationRetryCount++;
|
|
439
|
+
}
|
|
403
440
|
return {
|
|
404
441
|
step: 'Retry',
|
|
405
442
|
terminate: false,
|
|
406
443
|
errorMessage: `Actions '${missingActionNames}' not found or not active`
|
|
407
444
|
};
|
|
408
445
|
}
|
|
446
|
+
if (nextStep.actions) {
|
|
447
|
+
const violatedActions = [];
|
|
448
|
+
for (const action of nextStep.actions) {
|
|
449
|
+
const agentAction = curAgentActions.find(aa => aa.Action.trim().toLowerCase() === action.name.trim().toLowerCase());
|
|
450
|
+
if (agentAction && agentAction.MaxExecutionsPerRun != null) {
|
|
451
|
+
const executionCount = await this.getActionExecutionCount(agentRun.ID, agentAction.ActionID);
|
|
452
|
+
if (executionCount >= agentAction.MaxExecutionsPerRun) {
|
|
453
|
+
violatedActions.push(`${action.name} (limit: ${agentAction.MaxExecutionsPerRun}, current: ${executionCount})`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (violatedActions.length > 0) {
|
|
458
|
+
const violationMessage = `Actions have reached execution limits: ${violatedActions.join(', ')}`;
|
|
459
|
+
this.logError(violationMessage, {
|
|
460
|
+
agent: params.agent,
|
|
461
|
+
category: 'ActionExecution',
|
|
462
|
+
metadata: {
|
|
463
|
+
violatedActions
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
if (nextStep.step !== 'Retry') {
|
|
467
|
+
this._generalValidationRetryCount++;
|
|
468
|
+
}
|
|
469
|
+
return {
|
|
470
|
+
step: 'Retry',
|
|
471
|
+
terminate: false,
|
|
472
|
+
errorMessage: violationMessage
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
}
|
|
409
476
|
return nextStep;
|
|
410
477
|
}
|
|
411
|
-
async validateSuccessNextStep(params, nextStep, currentPayload) {
|
|
478
|
+
async validateSuccessNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
|
|
479
|
+
const minViolations = await this.checkMinimumExecutionRequirements(params.agent, agentRun);
|
|
480
|
+
if (minViolations.length > 0) {
|
|
481
|
+
const violationMessage = `Minimum execution requirements not met:\n${minViolations.join('\n')}`;
|
|
482
|
+
this.logError(violationMessage, {
|
|
483
|
+
agent: params.agent,
|
|
484
|
+
category: 'MinimumExecutionValidation'
|
|
485
|
+
});
|
|
486
|
+
if (nextStep.step !== 'Retry') {
|
|
487
|
+
this._generalValidationRetryCount++;
|
|
488
|
+
}
|
|
489
|
+
return {
|
|
490
|
+
step: 'Retry',
|
|
491
|
+
terminate: false,
|
|
492
|
+
errorMessage: violationMessage
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
const agent = params.agent;
|
|
496
|
+
if (!agent.FinalPayloadValidation || !currentPayload) {
|
|
497
|
+
return nextStep;
|
|
498
|
+
}
|
|
499
|
+
try {
|
|
500
|
+
let validationSchema;
|
|
501
|
+
try {
|
|
502
|
+
validationSchema = JSON.parse(agent.FinalPayloadValidation);
|
|
503
|
+
}
|
|
504
|
+
catch (parseError) {
|
|
505
|
+
this.logError(`Invalid FinalPayloadValidation JSON for agent ${agent.Name}: ${parseError.message}`, {
|
|
506
|
+
category: 'PayloadValidation',
|
|
507
|
+
metadata: {
|
|
508
|
+
agentName: agent.Name,
|
|
509
|
+
agentId: agent.ID,
|
|
510
|
+
validationSchema: agent.FinalPayloadValidation
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
return nextStep;
|
|
514
|
+
}
|
|
515
|
+
let payloadToValidate = currentPayload;
|
|
516
|
+
if (agent.PayloadScope) {
|
|
517
|
+
payloadToValidate = this._payloadManager.applyPayloadScope(currentPayload, agent.PayloadScope);
|
|
518
|
+
if (payloadToValidate === null) {
|
|
519
|
+
const errorMessage = `PayloadScope '${agent.PayloadScope}' not found in payload`;
|
|
520
|
+
return this.handleFinalPayloadValidationFailure(params, nextStep, currentPayload, agent.FinalPayloadValidationMode || 'Retry', [errorMessage], agentRun, currentStep);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
const jsonValidator = new global_1.JSONValidator();
|
|
524
|
+
const validationResult = jsonValidator.validate(payloadToValidate, validationSchema);
|
|
525
|
+
if (!validationResult.Success) {
|
|
526
|
+
const mode = agent.FinalPayloadValidationMode || 'Retry';
|
|
527
|
+
const errorMessages = validationResult.Errors.map(e => e.Message);
|
|
528
|
+
this.logStatus(`⚠️ Final payload validation failed for agent ${agent.Name} (mode: ${mode}):`, true, params);
|
|
529
|
+
errorMessages.forEach((error, index) => {
|
|
530
|
+
this.logStatus(` ${index + 1}. ${error}`, true, params);
|
|
531
|
+
});
|
|
532
|
+
return this.handleFinalPayloadValidationFailure(params, nextStep, currentPayload, mode, errorMessages, agentRun, currentStep);
|
|
533
|
+
}
|
|
534
|
+
this.logStatus(`✅ Final payload validation passed for agent ${agent.Name}`, true, params);
|
|
535
|
+
try {
|
|
536
|
+
currentStep.FinalPayloadValidationResult = 'Pass';
|
|
537
|
+
currentStep.FinalPayloadValidationMessages = null;
|
|
538
|
+
await currentStep.Save();
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
this.logError(`Failed to save validation success result: ${error.message}`, {
|
|
542
|
+
category: 'PayloadValidation',
|
|
543
|
+
metadata: { stepId: currentStep.ID }
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
return nextStep;
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
this.logError(`Unexpected error during final payload validation: ${error.message}`, {
|
|
550
|
+
category: 'PayloadValidation',
|
|
551
|
+
metadata: {
|
|
552
|
+
agentName: agent.Name,
|
|
553
|
+
agentId: agent.ID,
|
|
554
|
+
error: error.message
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
return nextStep;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
async handleFinalPayloadValidationFailure(params, nextStep, currentPayload, mode, errorMessages, agentRun, currentStep) {
|
|
561
|
+
const validationFeedback = `Final payload validation failed:\n${errorMessages.map((e, i) => `${i + 1}. ${e}`).join('\n')}`;
|
|
562
|
+
try {
|
|
563
|
+
currentStep.FinalPayloadValidationMessages = errorMessages.join('; ');
|
|
564
|
+
switch (mode) {
|
|
565
|
+
case 'Retry':
|
|
566
|
+
this._validationRetryCount++;
|
|
567
|
+
const maxRetries = params.agent.FinalPayloadValidationMaxRetries || 3;
|
|
568
|
+
if (this._validationRetryCount >= maxRetries) {
|
|
569
|
+
this.logStatus(`❌ Max validation retries (${maxRetries}) exceeded, forcing failure`, false, params);
|
|
570
|
+
currentStep.FinalPayloadValidationResult = 'Fail';
|
|
571
|
+
await currentStep.Save();
|
|
572
|
+
return {
|
|
573
|
+
...nextStep,
|
|
574
|
+
step: 'Failed',
|
|
575
|
+
message: `${validationFeedback}\n\nMax validation retries (${maxRetries}) exceeded.`,
|
|
576
|
+
terminate: true
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
currentStep.FinalPayloadValidationResult = 'Retry';
|
|
580
|
+
await currentStep.Save();
|
|
581
|
+
this.logStatus(`🔄 Validation retry ${this._validationRetryCount}/${maxRetries}`, true, params);
|
|
582
|
+
return {
|
|
583
|
+
...nextStep,
|
|
584
|
+
step: 'Retry',
|
|
585
|
+
message: `${validationFeedback}\n\nRetry attempt ${this._validationRetryCount} of ${maxRetries}`,
|
|
586
|
+
terminate: false
|
|
587
|
+
};
|
|
588
|
+
case 'Fail':
|
|
589
|
+
currentStep.FinalPayloadValidationResult = 'Fail';
|
|
590
|
+
await currentStep.Save();
|
|
591
|
+
return {
|
|
592
|
+
...nextStep,
|
|
593
|
+
step: 'Failed',
|
|
594
|
+
message: validationFeedback,
|
|
595
|
+
terminate: true
|
|
596
|
+
};
|
|
597
|
+
case 'Warn':
|
|
598
|
+
this.logStatus(`⚠️ WARNING: ${validationFeedback}`, false, params);
|
|
599
|
+
currentStep.FinalPayloadValidationResult = 'Warn';
|
|
600
|
+
await currentStep.Save();
|
|
601
|
+
return nextStep;
|
|
602
|
+
default:
|
|
603
|
+
this._validationRetryCount++;
|
|
604
|
+
currentStep.FinalPayloadValidationResult = 'Retry';
|
|
605
|
+
await currentStep.Save();
|
|
606
|
+
return {
|
|
607
|
+
...nextStep,
|
|
608
|
+
step: 'Retry',
|
|
609
|
+
message: validationFeedback,
|
|
610
|
+
terminate: false
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
catch (error) {
|
|
615
|
+
this.logError(`Failed to save validation results: ${error.message}`, {
|
|
616
|
+
category: 'PayloadValidation',
|
|
617
|
+
metadata: { stepId: currentStep.ID }
|
|
618
|
+
});
|
|
619
|
+
return mode === 'Warn' ? nextStep : {
|
|
620
|
+
...nextStep,
|
|
621
|
+
step: mode === 'Fail' ? 'Failed' : 'Retry',
|
|
622
|
+
message: validationFeedback,
|
|
623
|
+
terminate: mode === 'Fail'
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async validateFailedNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
|
|
412
628
|
return nextStep;
|
|
413
629
|
}
|
|
414
|
-
async
|
|
630
|
+
async validateRetryNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
|
|
415
631
|
return nextStep;
|
|
416
632
|
}
|
|
417
|
-
async
|
|
633
|
+
async validateChatNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
|
|
418
634
|
return nextStep;
|
|
419
635
|
}
|
|
420
|
-
async
|
|
636
|
+
async checkExecutionGuardrails(params, nextStep, currentPayload, agentRun, currentStep) {
|
|
637
|
+
if (nextStep.step === 'Success' || nextStep.step === 'Failed' || nextStep.step === 'Chat') {
|
|
638
|
+
return nextStep;
|
|
639
|
+
}
|
|
640
|
+
const guardrailResult = await this.hasExceededAgentRunGuardrails(params, agentRun);
|
|
641
|
+
if (guardrailResult.exceeded) {
|
|
642
|
+
this.logStatus(`⛔ Execution guardrail exceeded: ${guardrailResult.reason}`, false, params);
|
|
643
|
+
try {
|
|
644
|
+
const outputData = currentStep.OutputData ? JSON.parse(currentStep.OutputData) : {};
|
|
645
|
+
currentStep.OutputData = JSON.stringify({
|
|
646
|
+
...outputData,
|
|
647
|
+
guardrailExceeded: {
|
|
648
|
+
type: guardrailResult.type,
|
|
649
|
+
limit: guardrailResult.limit,
|
|
650
|
+
current: guardrailResult.current,
|
|
651
|
+
reason: guardrailResult.reason,
|
|
652
|
+
timestamp: new Date().toISOString()
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
await currentStep.Save();
|
|
656
|
+
}
|
|
657
|
+
catch (error) {
|
|
658
|
+
this.logError(`Failed to save guardrail violation to step: ${error.message}`, {
|
|
659
|
+
category: 'Guardrails',
|
|
660
|
+
metadata: { stepId: currentStep.ID }
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
return {
|
|
664
|
+
...nextStep,
|
|
665
|
+
step: 'Failed',
|
|
666
|
+
terminate: true,
|
|
667
|
+
message: guardrailResult.reason,
|
|
668
|
+
errorMessage: guardrailResult.reason
|
|
669
|
+
};
|
|
670
|
+
}
|
|
421
671
|
return nextStep;
|
|
422
672
|
}
|
|
423
|
-
async
|
|
673
|
+
async hasExceededAgentRunGuardrails(params, agentRun) {
|
|
674
|
+
const agent = params.agent;
|
|
675
|
+
if (agent.MaxCostPerRun && agentRun.TotalCost) {
|
|
676
|
+
if (agentRun.TotalCost >= agent.MaxCostPerRun) {
|
|
677
|
+
return {
|
|
678
|
+
exceeded: true,
|
|
679
|
+
type: 'cost',
|
|
680
|
+
limit: agent.MaxCostPerRun,
|
|
681
|
+
current: agentRun.TotalCost,
|
|
682
|
+
reason: `Maximum cost limit of $${agent.MaxCostPerRun} exceeded. Current cost: $${agentRun.TotalCost.toFixed(4)}`
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (agent.MaxTokensPerRun && agentRun.TotalTokensUsed) {
|
|
687
|
+
if (agentRun.TotalTokensUsed >= agent.MaxTokensPerRun) {
|
|
688
|
+
return {
|
|
689
|
+
exceeded: true,
|
|
690
|
+
type: 'tokens',
|
|
691
|
+
limit: agent.MaxTokensPerRun,
|
|
692
|
+
current: agentRun.TotalTokensUsed,
|
|
693
|
+
reason: `Maximum token limit of ${agent.MaxTokensPerRun} exceeded. Current tokens: ${agentRun.TotalTokensUsed}`
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (agent.MaxIterationsPerRun && agentRun.TotalPromptIterations) {
|
|
698
|
+
if (agentRun.TotalPromptIterations >= agent.MaxIterationsPerRun) {
|
|
699
|
+
return {
|
|
700
|
+
exceeded: true,
|
|
701
|
+
type: 'iterations',
|
|
702
|
+
limit: agent.MaxIterationsPerRun,
|
|
703
|
+
current: agentRun.TotalPromptIterations,
|
|
704
|
+
reason: `Maximum iteration limit of ${agent.MaxIterationsPerRun} exceeded. Current iterations: ${agentRun.TotalPromptIterations}`
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (agent.MaxTimePerRun && agentRun.StartedAt) {
|
|
709
|
+
const elapsedSeconds = Math.floor((Date.now() - new Date(agentRun.StartedAt).getTime()) / 1000);
|
|
710
|
+
if (elapsedSeconds >= agent.MaxTimePerRun) {
|
|
711
|
+
return {
|
|
712
|
+
exceeded: true,
|
|
713
|
+
type: 'time',
|
|
714
|
+
limit: agent.MaxTimePerRun,
|
|
715
|
+
current: elapsedSeconds,
|
|
716
|
+
reason: `Maximum time limit of ${agent.MaxTimePerRun} seconds exceeded. Elapsed time: ${elapsedSeconds} seconds`
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
if (this._generalValidationRetryCount >= BaseAgent.MAX_VALIDATION_RETRIES) {
|
|
721
|
+
return {
|
|
722
|
+
exceeded: true,
|
|
723
|
+
type: 'iterations',
|
|
724
|
+
limit: BaseAgent.MAX_VALIDATION_RETRIES,
|
|
725
|
+
current: this._generalValidationRetryCount,
|
|
726
|
+
reason: `Maximum validation retries of ${BaseAgent.MAX_VALIDATION_RETRIES} exceeded. The agent is unable to produce valid output after ${this._generalValidationRetryCount} validation failures.`
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
return { exceeded: false };
|
|
730
|
+
}
|
|
731
|
+
async processNextStep(params, agentType, promptResult, currentPayload, currentStep) {
|
|
424
732
|
const nextStep = await this.determineNextStep(params, agentType, promptResult, currentPayload);
|
|
425
|
-
const validatedNextStep = await this.validateNextStep(params, nextStep, currentPayload);
|
|
426
|
-
|
|
427
|
-
|
|
733
|
+
const validatedNextStep = await this.validateNextStep(params, nextStep, currentPayload, this._agentRun, currentStep);
|
|
734
|
+
const guardrailCheckedStep = await this.checkExecutionGuardrails(params, validatedNextStep, currentPayload, this._agentRun, currentStep);
|
|
735
|
+
this.logStatus(`📌 Next step determined: ${guardrailCheckedStep.step}${guardrailCheckedStep.terminate ? ' (terminating)' : ''}`, true, params);
|
|
736
|
+
if (guardrailCheckedStep.step === 'Retry' && (guardrailCheckedStep.message || guardrailCheckedStep.errorMessage || guardrailCheckedStep.retryInstructions)) {
|
|
737
|
+
params.conversationMessages.push({
|
|
738
|
+
role: 'user',
|
|
739
|
+
content: `Retrying due to: ${guardrailCheckedStep.retryInstructions || guardrailCheckedStep.message || guardrailCheckedStep.errorMessage}`
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
return guardrailCheckedStep;
|
|
428
743
|
}
|
|
429
744
|
createActionResultMessage(actions, results) {
|
|
430
745
|
const resultSummary = actions.map((action, index) => {
|
|
@@ -913,6 +1228,9 @@ class BaseAgent {
|
|
|
913
1228
|
stepEntity.TargetLogID = promptResult.promptRun.ID;
|
|
914
1229
|
stepEntity.PromptRun = promptResult.promptRun;
|
|
915
1230
|
}
|
|
1231
|
+
if (this._agentRun) {
|
|
1232
|
+
this._agentRun.TotalPromptIterations = (this._agentRun.TotalPromptIterations || 0) + 1;
|
|
1233
|
+
}
|
|
916
1234
|
if (params.cancellationToken?.aborted) {
|
|
917
1235
|
await this.finalizeStepEntity(stepEntity, false, 'Cancelled during prompt execution');
|
|
918
1236
|
const cancelledResult = await this.createCancelledResult('Cancelled during prompt execution', params.contextUser);
|
|
@@ -930,7 +1248,7 @@ class BaseAgent {
|
|
|
930
1248
|
message: this.formatHierarchicalMessage('Analyzing response and determining next steps'),
|
|
931
1249
|
displayMode: 'both'
|
|
932
1250
|
});
|
|
933
|
-
const nextStep = await this.processNextStep(params, config.agentType, promptResult, payload);
|
|
1251
|
+
const nextStep = await this.processNextStep(params, config.agentType, promptResult, payload, stepEntity);
|
|
934
1252
|
let finalPayload = payload;
|
|
935
1253
|
let currentStepPayloadChangeResult = undefined;
|
|
936
1254
|
if (nextStep.payloadChangeRequest) {
|
|
@@ -1023,6 +1341,7 @@ class BaseAgent {
|
|
|
1023
1341
|
throw new Error(`Sub-agent '${subAgentRequest.name}' not found`);
|
|
1024
1342
|
}
|
|
1025
1343
|
const stepEntity = await this.createStepEntity('Sub-Agent', `Execute Sub-Agent: ${subAgentRequest.name}`, params.contextUser, subAgentEntity.ID, inputData);
|
|
1344
|
+
this.incrementExecutionCount(subAgentEntity.ID);
|
|
1026
1345
|
try {
|
|
1027
1346
|
let downstreamPaths = ['*'];
|
|
1028
1347
|
let upstreamPaths = ['*'];
|
|
@@ -1046,10 +1365,31 @@ class BaseAgent {
|
|
|
1046
1365
|
}
|
|
1047
1366
|
});
|
|
1048
1367
|
}
|
|
1049
|
-
|
|
1368
|
+
let downstreamPayload = this._payloadManager.extractDownstreamPayload(subAgentRequest.name, previousDecision.newPayload, downstreamPaths);
|
|
1369
|
+
let scopedPayload = downstreamPayload;
|
|
1370
|
+
if (subAgentEntity.PayloadScope) {
|
|
1371
|
+
scopedPayload = this._payloadManager.applyPayloadScope(downstreamPayload, subAgentEntity.PayloadScope);
|
|
1372
|
+
if (scopedPayload === null) {
|
|
1373
|
+
const errorMessage = `Critical: Failed to extract payload scope '${subAgentEntity.PayloadScope}' for sub-agent '${subAgentRequest.name}'. The specified path does not exist in the payload.`;
|
|
1374
|
+
this.logError(errorMessage, {
|
|
1375
|
+
category: 'SubAgentExecution',
|
|
1376
|
+
metadata: {
|
|
1377
|
+
agentName: params.agent.Name,
|
|
1378
|
+
subAgentName: subAgentRequest.name,
|
|
1379
|
+
payloadScope: subAgentEntity.PayloadScope,
|
|
1380
|
+
availableKeys: Object.keys(downstreamPayload || {})
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
throw new Error(errorMessage);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1050
1386
|
stepEntity.PayloadAtStart = JSON.stringify(previousDecision.newPayload);
|
|
1051
|
-
const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity,
|
|
1052
|
-
|
|
1387
|
+
const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity, scopedPayload);
|
|
1388
|
+
let resultPayloadForMerge = subAgentResult.payload;
|
|
1389
|
+
if (subAgentEntity.PayloadScope) {
|
|
1390
|
+
resultPayloadForMerge = this._payloadManager.reversePayloadScope(subAgentResult.payload, subAgentEntity.PayloadScope);
|
|
1391
|
+
}
|
|
1392
|
+
const mergedPayload = this._payloadManager.mergeUpstreamPayload(subAgentRequest.name, previousDecision.newPayload, resultPayloadForMerge, upstreamPaths);
|
|
1053
1393
|
const mergeChangeRequest = {
|
|
1054
1394
|
newElements: {},
|
|
1055
1395
|
updateElements: {},
|
|
@@ -1216,6 +1556,7 @@ class BaseAgent {
|
|
|
1216
1556
|
}
|
|
1217
1557
|
const stepEntity = await this.createStepEntity('Actions', `Execute Action: ${aa.name}`, params.contextUser, actionEntity.ID);
|
|
1218
1558
|
stepEntity.StepNumber = baseStepNumber + numActionsProcessed++;
|
|
1559
|
+
this.incrementExecutionCount(actionEntity.ID);
|
|
1219
1560
|
let actionResult;
|
|
1220
1561
|
try {
|
|
1221
1562
|
actionResult = await this.ExecuteSingleAction(params, aa, actionEntity, params.contextUser);
|
|
@@ -1377,6 +1718,42 @@ class BaseAgent {
|
|
|
1377
1718
|
}
|
|
1378
1719
|
return { totalTokens, promptTokens, completionTokens, totalCost };
|
|
1379
1720
|
}
|
|
1721
|
+
async getActionExecutionCount(agentRunId, actionId) {
|
|
1722
|
+
return this.getExecutionCount(actionId);
|
|
1723
|
+
}
|
|
1724
|
+
async getSubAgentExecutionCount(agentRunId, subAgentId) {
|
|
1725
|
+
return this.getExecutionCount(subAgentId);
|
|
1726
|
+
}
|
|
1727
|
+
incrementExecutionCount(itemId) {
|
|
1728
|
+
const currentCount = this._executionCounts.get(itemId) || 0;
|
|
1729
|
+
this._executionCounts.set(itemId, currentCount + 1);
|
|
1730
|
+
}
|
|
1731
|
+
getExecutionCount(itemId) {
|
|
1732
|
+
return this._executionCounts.get(itemId) || 0;
|
|
1733
|
+
}
|
|
1734
|
+
async checkMinimumExecutionRequirements(agent, agentRun) {
|
|
1735
|
+
const violations = [];
|
|
1736
|
+
const agentActions = aiengine_1.AIEngine.Instance.AgentActions.filter(aa => aa.AgentID === agent.ID &&
|
|
1737
|
+
aa.Status === 'Active' &&
|
|
1738
|
+
aa.MinExecutionsPerRun != null &&
|
|
1739
|
+
aa.MinExecutionsPerRun > 0);
|
|
1740
|
+
for (const agentAction of agentActions) {
|
|
1741
|
+
const executionCount = await this.getActionExecutionCount(agentRun.ID, agentAction.ActionID);
|
|
1742
|
+
if (executionCount < agentAction.MinExecutionsPerRun) {
|
|
1743
|
+
violations.push(`Action '${agentAction.Action}' requires ${agentAction.MinExecutionsPerRun} execution(s) but was executed ${executionCount} time(s)`);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
const subAgents = aiengine_1.AIEngine.Instance.GetSubAgents(agent.ID, "Active").filter(a => a.MinExecutionsPerRun != null &&
|
|
1747
|
+
a.MinExecutionsPerRun > 0);
|
|
1748
|
+
for (const subAgent of subAgents) {
|
|
1749
|
+
const executionCount = await this.getSubAgentExecutionCount(agentRun.ID, subAgent.ID);
|
|
1750
|
+
if (executionCount < subAgent.MinExecutionsPerRun) {
|
|
1751
|
+
violations.push(`Sub-agent '${subAgent.Name}' requires ${subAgent.MinExecutionsPerRun} execution(s) but was executed ${executionCount} time(s)`);
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
return violations;
|
|
1755
|
+
}
|
|
1380
1756
|
}
|
|
1381
1757
|
exports.BaseAgent = BaseAgent;
|
|
1758
|
+
BaseAgent.MAX_VALIDATION_RETRIES = 10;
|
|
1382
1759
|
//# sourceMappingURL=base-agent.js.map
|