@memberjunction/ai-agents 5.4.0 → 5.5.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.
@@ -13,7 +13,7 @@
13
13
  import { Metadata, RunView, LogStatus, LogStatusEx, LogError, LogErrorEx, IsVerboseLoggingEnabled } from '@memberjunction/core';
14
14
  import { AIPromptRunner } from '@memberjunction/ai-prompts';
15
15
  import { BaseAgentType } from './agent-types/base-agent-type.js';
16
- import { CopyScalarsAndArrays, JSONValidator, SafeExpressionEvaluator } from '@memberjunction/global';
16
+ import { CopyScalarsAndArrays, JSONValidator, SafeExpressionEvaluator, UUIDsEqual } from '@memberjunction/global';
17
17
  import { AIEngine } from '@memberjunction/aiengine';
18
18
  import { ActionEngineServer } from '@memberjunction/actions';
19
19
  import { AIAgentPermissionHelper } from '@memberjunction/ai-engine-base';
@@ -1340,7 +1340,7 @@ export class BaseAgent {
1340
1340
  metadataOptional = true;
1341
1341
  }
1342
1342
  // Find the agent type
1343
- const agentType = engine.AgentTypes.find(at => at.ID === agent.TypeID);
1343
+ const agentType = engine.AgentTypes.find(at => UUIDsEqual(at.ID, agent.TypeID));
1344
1344
  if (!agentType && !metadataOptional) {
1345
1345
  return {
1346
1346
  success: false,
@@ -1351,13 +1351,13 @@ export class BaseAgent {
1351
1351
  const agentTypeInstance = await BaseAgentType.GetAgentTypeInstance(agentType);
1352
1352
  const requiresAgentLevelPrompts = agentTypeInstance.RequiresAgentLevelPrompts;
1353
1353
  // Find the system prompt (optional for some agent types)
1354
- const systemPrompt = engine.Prompts.find(p => p.ID === agentType.SystemPromptID);
1354
+ const systemPrompt = engine.Prompts.find(p => UUIDsEqual(p.ID, agentType.SystemPromptID));
1355
1355
  if (!systemPrompt) {
1356
1356
  metadataOptional = true; // If no system prompt, we can skip some validations
1357
1357
  }
1358
1358
  // Find the first active agent prompt (optional for agent types that don't require them)
1359
1359
  const agentPrompt = engine.AgentPrompts
1360
- .filter(ap => ap.AgentID === agent.ID && ap.Status === 'Active')
1360
+ .filter(ap => UUIDsEqual(ap.AgentID, agent.ID) && ap.Status === 'Active')
1361
1361
  .sort((a, b) => a.ExecutionOrder - b.ExecutionOrder)[0];
1362
1362
  if (!agentPrompt && !metadataOptional && requiresAgentLevelPrompts) {
1363
1363
  return {
@@ -1366,7 +1366,7 @@ export class BaseAgent {
1366
1366
  };
1367
1367
  }
1368
1368
  // Find the actual prompt entity (will be undefined for agent types with only step-level prompts)
1369
- const childPrompt = agentPrompt ? engine.Prompts.find(p => p.ID === agentPrompt.PromptID) : undefined;
1369
+ const childPrompt = agentPrompt ? engine.Prompts.find(p => UUIDsEqual(p.ID, agentPrompt.PromptID)) : undefined;
1370
1370
  if (!childPrompt && !metadataOptional && requiresAgentLevelPrompts) {
1371
1371
  return {
1372
1372
  success: false,
@@ -1654,7 +1654,7 @@ export class BaseAgent {
1654
1654
  // Fall back to database-configured actions if _effectiveActions is empty
1655
1655
  const effectiveActions = this.getEffectiveActionsForValidation(params.agent.ID);
1656
1656
  // Also get the database-configured agent actions for MaxExecutionsPerRun lookup
1657
- const dbAgentActions = AIEngine.Instance.AgentActions.filter(aa => aa.AgentID === params.agent.ID && aa.Status === 'Active');
1657
+ const dbAgentActions = AIEngine.Instance.AgentActions.filter(aa => UUIDsEqual(aa.AgentID, params.agent.ID) && aa.Status === 'Active');
1658
1658
  const missingActions = nextStep.actions?.filter(action => {
1659
1659
  const actionName = action.name.trim().toLowerCase();
1660
1660
  // Try exact match first against effective actions (by Name property)
@@ -1702,7 +1702,7 @@ export class BaseAgent {
1702
1702
  if (!actionEntity)
1703
1703
  continue;
1704
1704
  // Check for limit from database-configured agent action
1705
- const dbAgentAction = dbAgentActions.find(aa => aa.ActionID === actionEntity.ID);
1705
+ const dbAgentAction = dbAgentActions.find(aa => UUIDsEqual(aa.ActionID, actionEntity.ID));
1706
1706
  let maxExecutions = null;
1707
1707
  if (dbAgentAction?.MaxExecutionsPerRun != null) {
1708
1708
  // Database-configured action with limit
@@ -1756,8 +1756,8 @@ export class BaseAgent {
1756
1756
  return this._effectiveActions;
1757
1757
  }
1758
1758
  // Fallback: compute from database configuration
1759
- const agentActions = AIEngine.Instance.AgentActions.filter(aa => aa.AgentID === agentId && aa.Status === 'Active');
1760
- return ActionEngineServer.Instance.Actions.filter(a => agentActions.some(aa => aa.ActionID === a.ID) && a.Status === 'Active');
1759
+ const agentActions = AIEngine.Instance.AgentActions.filter(aa => UUIDsEqual(aa.AgentID, agentId) && aa.Status === 'Active');
1760
+ return ActionEngineServer.Instance.Actions.filter(a => agentActions.some(aa => UUIDsEqual(aa.ActionID, a.ID)) && a.Status === 'Active');
1761
1761
  }
1762
1762
  /**
1763
1763
  * Validates that the Success next step is valid and can be executed by the current agent. Subclasses can override
@@ -2874,18 +2874,18 @@ The context is now within limits. Please retry your request with the recovered c
2874
2874
  try {
2875
2875
  const engine = AIEngine.Instance;
2876
2876
  // Find sub-agents using AIEngine
2877
- const activeSubAgents = engine.Agents.filter(a => a.ParentID === agent.ID && a.Status === 'Active')
2877
+ const activeSubAgents = engine.Agents.filter(a => UUIDsEqual(a.ParentID, agent.ID) && a.Status === 'Active')
2878
2878
  .sort((a, b) => a.ExecutionOrder - b.ExecutionOrder);
2879
- const activeAgentRelationships = engine.AgentRelationships.filter(ar => ar.AgentID === agent.ID && ar.Status === 'Active');
2879
+ const activeAgentRelationships = engine.AgentRelationships.filter(ar => UUIDsEqual(ar.AgentID, agent.ID) && ar.Status === 'Active');
2880
2880
  // now combine the child sub-agents from the direct parentID relationships with the agentRelationships array, distinct to not repeat
2881
2881
  // unique ID values
2882
2882
  const uniqueActiveSubAgentIDs = new Set();
2883
2883
  activeSubAgents.forEach(a => uniqueActiveSubAgentIDs.add(a.ID));
2884
2884
  activeAgentRelationships.forEach(ar => uniqueActiveSubAgentIDs.add(ar.SubAgentID));
2885
- const uniqueActiveSubAgents = Array.from(uniqueActiveSubAgentIDs).map(id => engine.Agents.find(a => a.ID === id));
2885
+ const uniqueActiveSubAgents = Array.from(uniqueActiveSubAgentIDs).map(id => engine.Agents.find(a => UUIDsEqual(a.ID, id)));
2886
2886
  // Load available actions from database configuration
2887
- const agentActions = engine.AgentActions.filter(aa => aa.AgentID === agent.ID && aa.Status === 'Active');
2888
- let actions = ActionEngineServer.Instance.Actions.filter(a => agentActions.some(aa => aa.ActionID === a.ID));
2887
+ const agentActions = engine.AgentActions.filter(aa => UUIDsEqual(aa.AgentID, agent.ID) && aa.Status === 'Active');
2888
+ let actions = ActionEngineServer.Instance.Actions.filter(a => agentActions.some(aa => UUIDsEqual(aa.ActionID, a.ID)));
2889
2889
  // Apply runtime action changes if provided
2890
2890
  if (actionChanges?.length) {
2891
2891
  const isRoot = this._depth === 0;
@@ -2897,7 +2897,7 @@ The context is now within limits. Please retry your request with the recovered c
2897
2897
  const activeActions = actions.filter(a => a.Status === 'Active');
2898
2898
  this._effectiveActions = activeActions;
2899
2899
  // Build agent type prompt params (merged from schema defaults, agent config, and runtime overrides)
2900
- const agentType = engine.AgentTypes.find(at => at.ID === agent.TypeID);
2900
+ const agentType = engine.AgentTypes.find(at => UUIDsEqual(at.ID, agent.TypeID));
2901
2901
  const runtimePromptParamOverrides = extraData?.__agentTypePromptParams;
2902
2902
  const agentTypePromptParams = this.buildAgentTypePromptParams(agentType, agent, runtimePromptParamOverrides);
2903
2903
  const contextData = {
@@ -3146,7 +3146,7 @@ The context is now within limits. Please retry your request with the recovered c
3146
3146
  const engine = AIEngine.Instance;
3147
3147
  let messages = [];
3148
3148
  // Check for related sub-agent configuration (AIAgentRelationship)
3149
- const relationship = engine.AgentRelationships.find(r => r.AgentID === params.agent.ID && r.SubAgentID === subAgent.ID);
3149
+ const relationship = engine.AgentRelationships.find(r => UUIDsEqual(r.AgentID, params.agent.ID) && UUIDsEqual(r.SubAgentID, subAgent.ID));
3150
3150
  // Get MessageMode and MaxMessages from either relationship or child agent
3151
3151
  let messageMode = relationship?.MessageMode || subAgent.MessageMode || 'None';
3152
3152
  let maxMessages = relationship?.MaxMessages || subAgent.MaxMessages || null;
@@ -3338,11 +3338,11 @@ The context is now within limits. Please retry your request with the recovered c
3338
3338
  getAgentPromptParameters(agent) {
3339
3339
  const engine = AIEngine.Instance;
3340
3340
  const agentPrompt = engine.AgentPrompts
3341
- .filter(ap => ap.AgentID === agent.ID && ap.Status === 'Active')
3341
+ .filter(ap => UUIDsEqual(ap.AgentID, agent.ID) && ap.Status === 'Active')
3342
3342
  .sort((a, b) => a.ExecutionOrder - b.ExecutionOrder)[0];
3343
3343
  if (!agentPrompt)
3344
3344
  return [];
3345
- const prompt = engine.Prompts.find(p => p.ID === agentPrompt.PromptID);
3345
+ const prompt = engine.Prompts.find(p => UUIDsEqual(p.ID, agentPrompt.PromptID));
3346
3346
  if (!prompt)
3347
3347
  return [];
3348
3348
  // Return parameters as key-value pairs
@@ -3446,7 +3446,7 @@ The context is now within limits. Please retry your request with the recovered c
3446
3446
  * @private
3447
3447
  */
3448
3448
  getAgentTypeName(typeID) {
3449
- const agentType = AIEngine.Instance.AgentTypes.find(at => at.ID === typeID);
3449
+ const agentType = AIEngine.Instance.AgentTypes.find(at => UUIDsEqual(at.ID, typeID));
3450
3450
  return agentType?.Name || 'Unknown';
3451
3451
  }
3452
3452
  /**
@@ -3490,8 +3490,8 @@ The context is now within limits. Please retry your request with the recovered c
3490
3490
  if (change.mode === 'add') {
3491
3491
  // Add actions that aren't already present
3492
3492
  for (const actionId of change.actionIds) {
3493
- if (!actions.some(a => a.ID === actionId)) {
3494
- const actionToAdd = ActionEngineServer.Instance.Actions.find(a => a.ID === actionId);
3493
+ if (!actions.some(a => UUIDsEqual(a.ID, actionId))) {
3494
+ const actionToAdd = ActionEngineServer.Instance.Actions.find(a => UUIDsEqual(a.ID, actionId));
3495
3495
  if (actionToAdd) {
3496
3496
  actions.push(actionToAdd);
3497
3497
  // Store execution limit if provided
@@ -3507,7 +3507,7 @@ The context is now within limits. Please retry your request with the recovered c
3507
3507
  }
3508
3508
  else if (change.mode === 'remove') {
3509
3509
  // Remove actions by ID
3510
- actions = actions.filter(a => !change.actionIds.includes(a.ID));
3510
+ actions = actions.filter(a => !change.actionIds.some(id => UUIDsEqual(id, a.ID)));
3511
3511
  }
3512
3512
  }
3513
3513
  return { actions, dynamicLimits };
@@ -4551,7 +4551,7 @@ The context is now within limits. Please retry your request with the recovered c
4551
4551
  };
4552
4552
  // Get sub-agent entity to access payload paths
4553
4553
  const subAgentEntity = AIEngine.Instance.Agents.find(a => a.Name === subAgentRequest.name &&
4554
- a.ParentID === params.agent.ID);
4554
+ UUIDsEqual(a.ParentID, params.agent.ID));
4555
4555
  if (!subAgentEntity) {
4556
4556
  throw new Error(`Sub-agent '${subAgentRequest.name}' not found`);
4557
4557
  }
@@ -4800,7 +4800,7 @@ The context is now within limits. Please retry your request with the recovered c
4800
4800
  };
4801
4801
  }
4802
4802
  // Find the sub-agent - check both child and related agents
4803
- const childAgents = AIEngine.Instance.Agents.filter(a => a.ParentID === params.agent.ID &&
4803
+ const childAgents = AIEngine.Instance.Agents.filter(a => UUIDsEqual(a.ParentID, params.agent.ID) &&
4804
4804
  a.Status === 'Active');
4805
4805
  const childAgent = childAgents.find(a => a.Name.trim().toLowerCase() === name.trim().toLowerCase());
4806
4806
  if (childAgent) {
@@ -4808,10 +4808,10 @@ The context is now within limits. Please retry your request with the recovered c
4808
4808
  return await this.executeChildSubAgentStep(params, previousDecision, parentStepId, subAgentPayloadOverride, stepCount);
4809
4809
  }
4810
4810
  // Check for related agent
4811
- const activeRelationships = AIEngine.Instance.AgentRelationships.filter(ar => ar.AgentID === params.agent.ID &&
4811
+ const activeRelationships = AIEngine.Instance.AgentRelationships.filter(ar => UUIDsEqual(ar.AgentID, params.agent.ID) &&
4812
4812
  ar.Status === 'Active');
4813
4813
  for (const relationship of activeRelationships) {
4814
- const relatedAgent = AIEngine.Instance.Agents.find(a => a.ID === relationship.SubAgentID &&
4814
+ const relatedAgent = AIEngine.Instance.Agents.find(a => UUIDsEqual(a.ID, relationship.SubAgentID) &&
4815
4815
  a.Status === 'Active');
4816
4816
  if (relatedAgent && relatedAgent.Name.trim().toLowerCase() === name.trim().toLowerCase()) {
4817
4817
  // This is a related agent - use message-based coupling
@@ -5327,12 +5327,12 @@ The context is now within limits. Please retry your request with the recovered c
5327
5327
  }
5328
5328
  const actionEngine = ActionEngineServer.Instance;
5329
5329
  // Get the AIAgentAction metadata records for this agent (used for expiration settings)
5330
- const agentActions = AIEngine.Instance.AgentActions.filter(aa => aa.AgentID === params.agent.ID);
5330
+ const agentActions = AIEngine.Instance.AgentActions.filter(aa => UUIDsEqual(aa.AgentID, params.agent.ID));
5331
5331
  // Use _effectiveActions which includes runtime action changes applied in gatherPromptTemplateData
5332
5332
  // Fall back to database-configured actions if _effectiveActions is empty (shouldn't happen in normal flow)
5333
5333
  const effectiveActions = this._effectiveActions.length > 0
5334
5334
  ? this._effectiveActions
5335
- : actionEngine.Actions.filter(a => agentActions.some(aa => aa.ActionID === a.ID));
5335
+ : actionEngine.Actions.filter(a => agentActions.some(aa => UUIDsEqual(aa.ActionID, a.ID)));
5336
5336
  // Call agent type's pre-processing for actions
5337
5337
  try {
5338
5338
  const currentPayload = previousDecision?.newPayload || previousDecision?.previousPayload || params.payload;
@@ -5424,7 +5424,7 @@ The context is now within limits. Please retry your request with the recovered c
5424
5424
  // If multiple actions, use the most restrictive (shortest) expiration settings
5425
5425
  let metadata;
5426
5426
  const agentActionConfigs = actionResults
5427
- .map(r => agentActions.find(aa => aa.ActionID === r.actionEntity.ID))
5427
+ .map(r => agentActions.find(aa => UUIDsEqual(aa.ActionID, r.actionEntity.ID)))
5428
5428
  .filter(aa => aa != null);
5429
5429
  if (agentActionConfigs.length > 0) {
5430
5430
  // Find the most restrictive expiration settings
@@ -5629,8 +5629,8 @@ The context is now within limits. Please retry your request with the recovered c
5629
5629
  }
5630
5630
  validateSubAgentInAgent(subAgentName) {
5631
5631
  // check to make sure sub-agent is valid
5632
- const relatedAgents = AIEngine.Instance.AgentRelationships.filter(ar => ar.AgentID === this._agentRun.AgentID);
5633
- const childAgents = AIEngine.Instance.Agents.filter(a => a.ParentID === this._agentRun.AgentID);
5632
+ const relatedAgents = AIEngine.Instance.AgentRelationships.filter(ar => UUIDsEqual(ar.AgentID, this._agentRun.AgentID));
5633
+ const childAgents = AIEngine.Instance.Agents.filter(a => UUIDsEqual(a.ParentID, this._agentRun.AgentID));
5634
5634
  // now check to make sure that subAgentName is either in relatedAgents or childAgents
5635
5635
  let subAgent = relatedAgents.filter(ra => ra.SubAgent?.trim().toLowerCase() === subAgentName.trim().toLowerCase());
5636
5636
  if (subAgent.length === 0) {
@@ -6268,7 +6268,7 @@ The context is now within limits. Please retry your request with the recovered c
6268
6268
  const violations = [];
6269
6269
  // Check action minimum requirements from database-configured actions only.
6270
6270
  // Dynamically added actions do not have MinExecutionsPerRun requirements.
6271
- const agentActions = AIEngine.Instance.AgentActions.filter(aa => aa.AgentID === agent.ID &&
6271
+ const agentActions = AIEngine.Instance.AgentActions.filter(aa => UUIDsEqual(aa.AgentID, agent.ID) &&
6272
6272
  aa.Status === 'Active' &&
6273
6273
  aa.MinExecutionsPerRun != null &&
6274
6274
  aa.MinExecutionsPerRun > 0);
@@ -6491,7 +6491,7 @@ The context is now within limits. Please retry your request with the recovered c
6491
6491
  // 3. Action.DefaultCompactPromptID
6492
6492
  // 4. System default compact prompt
6493
6493
  const promptId = metadata.compactPromptId || this.getSystemDefaultCompactPromptId();
6494
- const prompt = AIEngine.Instance.Prompts.find(p => p.ID === promptId);
6494
+ const prompt = AIEngine.Instance.Prompts.find(p => UUIDsEqual(p.ID, promptId));
6495
6495
  if (!prompt) {
6496
6496
  // Fallback to First N Chars if prompt not found
6497
6497
  console.warn(`Compact prompt ${promptId} not found, falling back to First N Chars`);
@@ -6614,7 +6614,7 @@ The context is now within limits. Please retry your request with the recovered c
6614
6614
  return DEFAULT_LIMIT;
6615
6615
  }
6616
6616
  // Find the vendor-specific entry
6617
- const vendorEntry = modelVendors.find((mv) => mv.VendorID === vendorSelected.ID);
6617
+ const vendorEntry = modelVendors.find((mv) => UUIDsEqual(mv.VendorID, vendorSelected.ID));
6618
6618
  if (!vendorEntry) {
6619
6619
  this.logStatus(`No matching vendor entry found in ModelVendors, using default limit: ${DEFAULT_LIMIT}`, true);
6620
6620
  return DEFAULT_LIMIT;