@memberjunction/ai-agents 2.113.2 → 2.115.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.
@@ -477,20 +477,23 @@ class BaseAgent {
477
477
  errorMessage: `Agent type not found for ID: ${agent.TypeID}`
478
478
  };
479
479
  }
480
+ const agentTypeInstance = await base_agent_type_1.BaseAgentType.GetAgentTypeInstance(agentType);
481
+ const requiresAgentLevelPrompts = agentTypeInstance.RequiresAgentLevelPrompts;
480
482
  const systemPrompt = engine.Prompts.find(p => p.ID === agentType.SystemPromptID);
481
- if (!systemPrompt)
483
+ if (!systemPrompt) {
482
484
  metadataOptional = true;
485
+ }
483
486
  const agentPrompt = engine.AgentPrompts
484
487
  .filter(ap => ap.AgentID === agent.ID && ap.Status === 'Active')
485
488
  .sort((a, b) => a.ExecutionOrder - b.ExecutionOrder)[0];
486
- if (!agentPrompt && !metadataOptional) {
489
+ if (!agentPrompt && !metadataOptional && requiresAgentLevelPrompts) {
487
490
  return {
488
491
  success: false,
489
492
  errorMessage: `No prompts configured for agent: ${agent.Name}`
490
493
  };
491
494
  }
492
- const childPrompt = engine.Prompts.find(p => p.ID === agentPrompt?.PromptID);
493
- if (!childPrompt && !metadataOptional) {
495
+ const childPrompt = agentPrompt ? engine.Prompts.find(p => p.ID === agentPrompt.PromptID) : undefined;
496
+ if (!childPrompt && !metadataOptional && requiresAgentLevelPrompts) {
494
497
  return {
495
498
  success: false,
496
499
  errorMessage: `Child prompt not found for ID: ${agentPrompt?.PromptID}`
@@ -537,7 +540,7 @@ class BaseAgent {
537
540
  this.logStatus(`šŸŽÆ Using agent default effort level: ${params.agent.DefaultPromptEffortLevel}`, true, params);
538
541
  }
539
542
  else {
540
- if (childPrompt.EffortLevel !== undefined && childPrompt.EffortLevel !== null) {
543
+ if (childPrompt && childPrompt.EffortLevel !== undefined && childPrompt.EffortLevel !== null) {
541
544
  promptParams.effortLevel = childPrompt.EffortLevel;
542
545
  this.logStatus(`šŸŽÆ Using child prompt effort level: ${childPrompt.EffortLevel}`, true, params);
543
546
  }
@@ -969,6 +972,17 @@ class BaseAgent {
969
972
  }
970
973
  async hasExceededAgentRunGuardrails(params, agentRun) {
971
974
  const agent = params.agent;
975
+ const DEFAULT_ABSOLUTE_MAX_ITERATIONS = 5000;
976
+ const absoluteMaxIterations = params.absoluteMaxIterations ?? DEFAULT_ABSOLUTE_MAX_ITERATIONS;
977
+ if (agentRun.TotalPromptIterations && agentRun.TotalPromptIterations >= absoluteMaxIterations) {
978
+ return {
979
+ exceeded: true,
980
+ type: 'iterations',
981
+ limit: absoluteMaxIterations,
982
+ current: agentRun.TotalPromptIterations,
983
+ reason: `Absolute maximum iteration safety limit of ${absoluteMaxIterations} exceeded. Current iterations: ${agentRun.TotalPromptIterations}. This is a system-wide safety measure to prevent infinite loops.`
984
+ };
985
+ }
972
986
  if (agent.MaxCostPerRun && agentRun.TotalCost) {
973
987
  if (agentRun.TotalCost >= agent.MaxCostPerRun) {
974
988
  return {
@@ -1026,6 +1040,12 @@ class BaseAgent {
1026
1040
  return { exceeded: false };
1027
1041
  }
1028
1042
  isFatalPromptError(promptResult) {
1043
+ if (promptResult?.errorMessage) {
1044
+ const templateErrorPattern = /Failed to render/i;
1045
+ if (templateErrorPattern.test(promptResult.errorMessage)) {
1046
+ return true;
1047
+ }
1048
+ }
1029
1049
  if (!promptResult?.chatResult?.errorInfo) {
1030
1050
  return false;
1031
1051
  }
@@ -1040,6 +1060,128 @@ class BaseAgent {
1040
1060
  ];
1041
1061
  return fatalErrorTypes.includes(errorInfo.errorType);
1042
1062
  }
1063
+ isConfigurationError(errorMessage, config) {
1064
+ const configErrorPatterns = [
1065
+ {
1066
+ pattern: /cannot read propert(y|ies) of (undefined|null)/i,
1067
+ getMessage: () => {
1068
+ const propertyMatch = errorMessage.match(/reading '(\w+)'/i);
1069
+ const property = propertyMatch ? propertyMatch[1] : 'unknown property';
1070
+ let details = `Attempted to access property '${property}' on an undefined or null object.`;
1071
+ if (property.toLowerCase().includes('prompt')) {
1072
+ details += `\n\nšŸ”§ Configuration Issue: Missing prompt configuration.`;
1073
+ if (config) {
1074
+ if (!config.childPrompt) {
1075
+ details += `\n - Agent does not have a child prompt configured`;
1076
+ if (this.AgentTypeInstance) {
1077
+ const guidance = this.AgentTypeInstance.GetPromptConfigurationGuidance();
1078
+ details += `\n${guidance}`;
1079
+ }
1080
+ }
1081
+ if (!config.systemPrompt) {
1082
+ details += `\n - Agent type does not have a system prompt configured`;
1083
+ }
1084
+ }
1085
+ }
1086
+ else if (property.toLowerCase().includes('agent')) {
1087
+ details += `\n\nšŸ”§ Configuration Issue: Missing agent configuration.`;
1088
+ details += `\n - Ensure agent type is properly configured`;
1089
+ details += `\n - Check that agent metadata is complete`;
1090
+ }
1091
+ return details;
1092
+ }
1093
+ },
1094
+ {
1095
+ pattern: /childprompt is (undefined|null|not defined)/i,
1096
+ getMessage: () => {
1097
+ let details = `Agent is missing required child prompt configuration.\n\n` +
1098
+ `šŸ”§ Configuration Fix:\n`;
1099
+ if (this.AgentTypeInstance) {
1100
+ const guidance = this.AgentTypeInstance.GetPromptConfigurationGuidance();
1101
+ details += `${guidance}`;
1102
+ }
1103
+ else {
1104
+ details += ` - Ensure agent has AI Agent Prompts relationship configured\n` +
1105
+ ` - Verify that prompt exists in AI Prompts table and is active`;
1106
+ }
1107
+ return details;
1108
+ }
1109
+ },
1110
+ {
1111
+ pattern: /systemprompt is (undefined|null|not defined)/i,
1112
+ getMessage: () => {
1113
+ return `Agent type is missing system prompt configuration.\n\n` +
1114
+ `šŸ”§ Configuration Fix:\n` +
1115
+ ` - Check agent type's SystemPromptID in AI Agent Types table\n` +
1116
+ ` - Verify system prompt exists and is active\n` +
1117
+ ` - Some agent types (like Flow) may not require system prompts`;
1118
+ }
1119
+ },
1120
+ {
1121
+ pattern: /no prompts configured/i,
1122
+ getMessage: () => {
1123
+ return `Agent has no prompts configured.\n\n` +
1124
+ `šŸ”§ Configuration Fix:\n` +
1125
+ ` - Add at least one AI Agent Prompt relationship to this agent\n` +
1126
+ ` - Or for Flow agents: Add Prompt-type steps to the agent's step graph`;
1127
+ }
1128
+ },
1129
+ {
1130
+ pattern: /agent type not found/i,
1131
+ getMessage: () => {
1132
+ return `Agent references an agent type that doesn't exist.\n\n` +
1133
+ `šŸ”§ Configuration Fix:\n` +
1134
+ ` - Verify TypeID in AI Agents table matches existing AI Agent Types record\n` +
1135
+ ` - Check that AIEngine.Instance.AgentTypes includes the required type\n` +
1136
+ ` - Ensure Config() has been called to load agent types`;
1137
+ }
1138
+ },
1139
+ {
1140
+ pattern: /child prompt not found/i,
1141
+ getMessage: () => {
1142
+ return `Referenced child prompt doesn't exist or isn't loaded.\n\n` +
1143
+ `šŸ”§ Configuration Fix:\n` +
1144
+ ` - Check AI Agent Prompts relationship has valid PromptID\n` +
1145
+ ` - Verify prompt exists in AI Prompts table\n` +
1146
+ ` - Ensure AIEngine.Instance.Prompts includes the prompt`;
1147
+ }
1148
+ },
1149
+ {
1150
+ pattern: /agent configuration/i,
1151
+ getMessage: () => {
1152
+ return `General agent configuration error.\n\n` +
1153
+ `šŸ”§ Configuration Check:\n` +
1154
+ ` - Review agent metadata in AI Agents table\n` +
1155
+ ` - Check all foreign key relationships are valid\n` +
1156
+ ` - Verify agent type is properly configured`;
1157
+ }
1158
+ },
1159
+ {
1160
+ pattern: /Failed to render.*child prompt templates/i,
1161
+ getMessage: () => {
1162
+ return `Template rendering error: ${errorMessage}\n\n` +
1163
+ `šŸ”§ Template Configuration Fix:\n` +
1164
+ ` - Check nunjucks template syntax in prompt content\n` +
1165
+ ` - Use {% raw %}{{}}{% endraw %} for literal braces in examples\n` +
1166
+ ` - Verify all template variables are properly defined\n` +
1167
+ ` - Ensure template variables referenced in content exist in context`;
1168
+ }
1169
+ }
1170
+ ];
1171
+ for (const { pattern, getMessage } of configErrorPatterns) {
1172
+ if (pattern.test(errorMessage)) {
1173
+ const detailedMessage = getMessage();
1174
+ return {
1175
+ isConfigError: true,
1176
+ detailedMessage: `Configuration Error: ${detailedMessage}\n\nOriginal Error: ${errorMessage}`
1177
+ };
1178
+ }
1179
+ }
1180
+ return {
1181
+ isConfigError: false,
1182
+ detailedMessage: errorMessage
1183
+ };
1184
+ }
1043
1185
  contentToString(content) {
1044
1186
  if (typeof content === 'string') {
1045
1187
  return content;
@@ -1522,10 +1664,12 @@ The context is now within limits. Please retry your request with the recovered c
1522
1664
  if (contextMessage) {
1523
1665
  messages.push(contextMessage);
1524
1666
  }
1525
- messages.push({
1526
- role: 'user',
1527
- content: subAgentRequest.message
1528
- });
1667
+ if (subAgentRequest.message) {
1668
+ messages.push({
1669
+ role: 'user',
1670
+ content: subAgentRequest.message
1671
+ });
1672
+ }
1529
1673
  return messages;
1530
1674
  }
1531
1675
  async ExecuteSubAgent(params, subAgentRequest, subAgent, stepEntity, payload, contextMessage) {
@@ -1554,8 +1698,8 @@ The context is now within limits. Please retry your request with the recovered c
1554
1698
  configurationId: params.configurationId,
1555
1699
  effortLevel: params.effortLevel,
1556
1700
  data: {
1557
- ...subAgentRequest.templateParameters,
1558
1701
  ...params.data,
1702
+ ...subAgentRequest.templateParameters,
1559
1703
  },
1560
1704
  context: params.context,
1561
1705
  verbose: params.verbose,
@@ -1850,57 +1994,28 @@ The context is now within limits. Please retry your request with the recovered c
1850
1994
  };
1851
1995
  }
1852
1996
  async finalizeStepEntity(stepEntity, success, errorMessage, outputData) {
1853
- stepEntity.Status = success ? 'Completed' : 'Failed';
1854
- stepEntity.CompletedAt = new Date();
1855
- stepEntity.Success = success;
1856
- stepEntity.ErrorMessage = errorMessage || null;
1857
- if (outputData) {
1858
- stepEntity.OutputData = JSON.stringify({
1859
- ...outputData,
1860
- context: {
1861
- success,
1862
- durationMs: stepEntity.CompletedAt.getTime() - stepEntity.StartedAt.getTime(),
1863
- errorMessage
1864
- }
1865
- });
1866
- }
1867
- if (!await stepEntity.Save()) {
1868
- console.error('Failed to update agent run step record');
1869
- }
1870
- }
1871
- getValueFromPath(obj, path) {
1872
- const parts = path.split('.');
1873
- let current = obj;
1874
- for (const part of parts) {
1875
- if (!part)
1876
- continue;
1877
- const arrayMatch = part.match(/^([^[]+)\[(\d+)\]$/);
1878
- if (arrayMatch) {
1879
- const arrayName = arrayMatch[1];
1880
- const index = parseInt(arrayMatch[2], 10);
1881
- if (current && typeof current === 'object' && arrayName in current) {
1882
- current = current[arrayName];
1883
- if (Array.isArray(current) && index >= 0 && index < current.length) {
1884
- current = current[index];
1885
- }
1886
- else {
1887
- return undefined;
1997
+ try {
1998
+ stepEntity.Status = success ? 'Completed' : 'Failed';
1999
+ stepEntity.CompletedAt = new Date();
2000
+ stepEntity.Success = success;
2001
+ stepEntity.ErrorMessage = errorMessage || null;
2002
+ if (outputData) {
2003
+ stepEntity.OutputData = JSON.stringify({
2004
+ ...(0, global_1.CopyScalarsAndArrays)(outputData, true),
2005
+ context: {
2006
+ success,
2007
+ durationMs: stepEntity.CompletedAt.getTime() - stepEntity.StartedAt.getTime(),
2008
+ errorMessage
1888
2009
  }
1889
- }
1890
- else {
1891
- return undefined;
1892
- }
2010
+ });
1893
2011
  }
1894
- else {
1895
- if (current && typeof current === 'object' && part in current) {
1896
- current = current[part];
1897
- }
1898
- else {
1899
- return undefined;
1900
- }
2012
+ if (!await stepEntity.Save()) {
2013
+ console.error('Failed to update agent run step record');
1901
2014
  }
1902
2015
  }
1903
- return current;
2016
+ catch (e) {
2017
+ console.error('Failed to update agent run step record', e);
2018
+ }
1904
2019
  }
1905
2020
  resolveLoopParams(params, item, index, payload) {
1906
2021
  const resolved = {};
@@ -1982,7 +2097,28 @@ The context is now within limits. Please retry your request with the recovered c
1982
2097
  };
1983
2098
  }
1984
2099
  else {
1985
- return await this.executePromptStep(params, config, previousDecision);
2100
+ const fallbackStep = await this.AgentTypeInstance.HandleStepFallback(previousDecision, config, params, previousDecision.newPayload || previousDecision.previousPayload, this.AgentTypeState);
2101
+ if (fallbackStep) {
2102
+ if (fallbackStep.terminate) {
2103
+ const terminationMessage = `Agent completed successfully. Agent type '${config.agentType.Name}' terminated execution.`;
2104
+ const stepEntity = await this.createStepEntity({
2105
+ stepType: 'Decision',
2106
+ stepName: terminationMessage,
2107
+ contextUser: params.contextUser,
2108
+ payloadAtStart: fallbackStep.previousPayload,
2109
+ payloadAtEnd: fallbackStep.newPayload
2110
+ });
2111
+ await this.finalizeStepEntity(stepEntity, true, undefined, {
2112
+ reason: 'Agent type intervention - Success',
2113
+ agentType: config.agentType.Name,
2114
+ decision: 'Success'
2115
+ });
2116
+ }
2117
+ return fallbackStep;
2118
+ }
2119
+ else {
2120
+ return await this.executePromptStep(params, config, previousDecision);
2121
+ }
1986
2122
  }
1987
2123
  case 'Failed':
1988
2124
  if (previousDecision.terminate) {
@@ -1994,7 +2130,41 @@ The context is now within limits. Please retry your request with the recovered c
1994
2130
  };
1995
2131
  }
1996
2132
  else {
1997
- return await this.executePromptStep(params, config, previousDecision);
2133
+ const fallbackStep = await this.AgentTypeInstance.HandleStepFallback(previousDecision, config, params, previousDecision.newPayload || previousDecision.previousPayload, this.AgentTypeState);
2134
+ if (fallbackStep) {
2135
+ if (fallbackStep.terminate) {
2136
+ const errorDetails = fallbackStep.errorMessage || 'No error details provided';
2137
+ const terminationMessage = `Agent failed. Agent type '${config.agentType.Name}' terminated execution: ${errorDetails}`;
2138
+ const stepEntity = await this.createStepEntity({
2139
+ stepType: 'Decision',
2140
+ stepName: terminationMessage,
2141
+ contextUser: params.contextUser,
2142
+ payloadAtStart: fallbackStep.previousPayload,
2143
+ payloadAtEnd: fallbackStep.newPayload
2144
+ });
2145
+ await this.finalizeStepEntity(stepEntity, false, errorDetails, {
2146
+ reason: 'Agent type intervention - Failed',
2147
+ agentType: config.agentType.Name,
2148
+ decision: 'Failed'
2149
+ });
2150
+ if (this.AgentRun) {
2151
+ this.AgentRun.ErrorMessage = terminationMessage;
2152
+ await this.AgentRun.Save();
2153
+ }
2154
+ this.logError(`Agent type '${config.agentType.Name}' handling Failed step with termination`, {
2155
+ agent: params.agent,
2156
+ category: 'AgentExecution',
2157
+ metadata: {
2158
+ errorDetails,
2159
+ agentType: config.agentType.Name
2160
+ }
2161
+ });
2162
+ }
2163
+ return fallbackStep;
2164
+ }
2165
+ else {
2166
+ return await this.executePromptStep(params, config, previousDecision);
2167
+ }
1998
2168
  }
1999
2169
  case 'ForEach':
2000
2170
  return await this.executeForEachLoop(params, config, previousDecision);
@@ -2004,6 +2174,9 @@ The context is now within limits. Please retry your request with the recovered c
2004
2174
  throw new Error(`Unsupported next step: ${previousDecision.step}`);
2005
2175
  }
2006
2176
  }
2177
+ getDefaultPayloadSelfWritePaths() {
2178
+ return undefined;
2179
+ }
2007
2180
  async executePromptStep(params, config, previousDecision) {
2008
2181
  const promptToUse = await this.AgentTypeInstance.GetPromptForStep(params, config, previousDecision?.newPayload || previousDecision?.previousPayload, this.AgentTypeState, previousDecision);
2009
2182
  const promptId = promptToUse?.ID;
@@ -2116,7 +2289,7 @@ The context is now within limits. Please retry your request with the recovered c
2116
2289
  if (initialNextStep.payloadChangeRequest) {
2117
2290
  const allowedPaths = params.agent.PayloadSelfWritePaths
2118
2291
  ? JSON.parse(params.agent.PayloadSelfWritePaths)
2119
- : undefined;
2292
+ : this.getDefaultPayloadSelfWritePaths();
2120
2293
  const changeResult = this._payloadManager.applyAgentChangeRequest(payload, initialNextStep.payloadChangeRequest, {
2121
2294
  validateChanges: true,
2122
2295
  logChanges: true,
@@ -2165,24 +2338,107 @@ The context is now within limits. Please retry your request with the recovered c
2165
2338
  catch (error) {
2166
2339
  const payload = stepEntity.PayloadAtEnd ? JSON.parse(stepEntity.PayloadAtEnd) : previousDecision?.newPayload || params.payload;
2167
2340
  stepEntity.PayloadAtEnd = payload ? JSON.stringify(payload) : null;
2168
- await this.finalizeStepEntity(stepEntity, false, error.message);
2169
2341
  const errString = error?.message || error || 'Unknown error';
2342
+ const configCheck = this.isConfigurationError(errString, config);
2343
+ const isConfigurationError = configCheck.isConfigError;
2344
+ const detailedErrorMessage = configCheck.detailedMessage;
2345
+ const guardailCheck = await this.hasExceededAgentRunGuardrails(params, this.AgentRun);
2346
+ const guardrailsExceeded = guardailCheck && guardailCheck.exceeded;
2347
+ const shouldTerminate = isConfigurationError || guardrailsExceeded;
2348
+ let finalErrorMessage;
2349
+ if (isConfigurationError) {
2350
+ finalErrorMessage = detailedErrorMessage;
2351
+ this.logError(`āŒ Configuration error in prompt execution (will terminate):\n${detailedErrorMessage}`, {
2352
+ agent: params.agent,
2353
+ category: 'AgentConfiguration',
2354
+ metadata: {
2355
+ error: (0, global_1.CopyScalarsAndArrays)(error, true)
2356
+ }
2357
+ });
2358
+ }
2359
+ else if (guardrailsExceeded) {
2360
+ finalErrorMessage = `Guardrails exceeded: ${guardailCheck.reason}\n\nOriginal error: ${errString}`;
2361
+ this.logError(`ā›” Guardrails exceeded during prompt execution: ${guardailCheck.reason}`, {
2362
+ agent: params.agent,
2363
+ category: 'Guardrails',
2364
+ metadata: {
2365
+ guardrailType: guardailCheck.type,
2366
+ limit: guardailCheck.limit,
2367
+ current: guardailCheck.current,
2368
+ originalError: errString
2369
+ }
2370
+ });
2371
+ }
2372
+ else {
2373
+ finalErrorMessage = `Prompt execution failed: ${errString}`;
2374
+ this.logError(`āš ļø Prompt execution error (will retry if guardrails allow): ${errString}`, {
2375
+ agent: params.agent,
2376
+ category: 'PromptExecution',
2377
+ metadata: {
2378
+ attemptNumber: this._agentRun?.TotalPromptIterations || 0,
2379
+ retryable: true,
2380
+ error: (0, global_1.CopyScalarsAndArrays)(error, true)
2381
+ }
2382
+ });
2383
+ }
2384
+ await this.finalizeStepEntity(stepEntity, false, finalErrorMessage);
2170
2385
  const errorNextStep = {
2171
- errorMessage: `Prompt execution failed: ${errString}`,
2386
+ errorMessage: finalErrorMessage,
2172
2387
  step: 'Failed',
2173
- terminate: false,
2388
+ terminate: shouldTerminate,
2174
2389
  previousPayload: payload,
2175
2390
  newPayload: payload
2176
2391
  };
2177
- const guardailCheck = await this.hasExceededAgentRunGuardrails(params, this.AgentRun);
2178
- if (guardailCheck && guardailCheck.exceeded) {
2179
- errorNextStep.terminate = true;
2180
- }
2181
- ;
2182
2392
  return errorNextStep;
2183
2393
  }
2184
2394
  }
2185
- async executeChildSubAgentStep(params, previousDecision) {
2395
+ computeUpstreamDownstreamPaths(params, subAgentEntity, subAgentRequest) {
2396
+ let downstreamPaths = ['*'];
2397
+ let upstreamPaths = ['*'];
2398
+ try {
2399
+ if (subAgentEntity.PayloadDownstreamPaths) {
2400
+ downstreamPaths = JSON.parse(subAgentEntity.PayloadDownstreamPaths);
2401
+ }
2402
+ if (subAgentEntity.PayloadUpstreamPaths) {
2403
+ upstreamPaths = JSON.parse(subAgentEntity.PayloadUpstreamPaths);
2404
+ }
2405
+ }
2406
+ catch (parseError) {
2407
+ this.logError(`Failed to parse payload paths for sub-agent ${subAgentRequest.name}: ${parseError.message}`, {
2408
+ category: 'SubAgentExecution',
2409
+ metadata: {
2410
+ agentName: params.agent.Name,
2411
+ subAgentName: subAgentRequest.name,
2412
+ subAgentId: subAgentEntity.ID,
2413
+ downstreamPaths: subAgentEntity.PayloadDownstreamPaths,
2414
+ upstreamPaths: subAgentEntity.PayloadUpstreamPaths
2415
+ }
2416
+ });
2417
+ }
2418
+ return { downstreamPaths, upstreamPaths };
2419
+ }
2420
+ async computeChildSubAgentPayload(params, subAgentEntity, downstreamPaths, subAgentRequest, previousDecision) {
2421
+ let downstreamPayload = this._payloadManager.extractDownstreamPayload(subAgentRequest.name, previousDecision.newPayload, downstreamPaths);
2422
+ let scopedPayload = downstreamPayload;
2423
+ if (subAgentEntity.PayloadScope) {
2424
+ scopedPayload = this._payloadManager.applyPayloadScope(downstreamPayload, subAgentEntity.PayloadScope);
2425
+ if (scopedPayload === null) {
2426
+ const errorMessage = `Critical: Failed to extract payload scope '${subAgentEntity.PayloadScope}' for sub-agent '${subAgentRequest.name}'. The specified path does not exist in the payload.`;
2427
+ this.logError(errorMessage, {
2428
+ category: 'SubAgentExecution',
2429
+ metadata: {
2430
+ agentName: params.agent.Name,
2431
+ subAgentName: subAgentRequest.name,
2432
+ payloadScope: subAgentEntity.PayloadScope,
2433
+ availableKeys: Object.keys(downstreamPayload || {})
2434
+ }
2435
+ });
2436
+ throw new Error(errorMessage);
2437
+ }
2438
+ }
2439
+ return scopedPayload;
2440
+ }
2441
+ async executeChildSubAgentStep(params, previousDecision, parentStepId, subAgentPayloadOverride) {
2186
2442
  const subAgentRequest = previousDecision.subAgent;
2187
2443
  if (params.cancellationToken?.aborted) {
2188
2444
  throw new Error('Cancelled before sub-agent execution');
@@ -2214,48 +2470,16 @@ The context is now within limits. Please retry your request with the recovered c
2214
2470
  if (!subAgentEntity) {
2215
2471
  throw new Error(`Sub-agent '${subAgentRequest.name}' not found`);
2216
2472
  }
2217
- const stepEntity = await this.createStepEntity({ stepType: 'Sub-Agent', stepName: `Execute Sub-Agent: ${subAgentRequest.name}`, contextUser: params.contextUser, targetId: subAgentEntity.ID, inputData, payloadAtStart: previousDecision.newPayload });
2473
+ const stepEntity = await this.createStepEntity({ stepType: 'Sub-Agent', stepName: `Execute Sub-Agent: ${subAgentRequest.name}`, contextUser: params.contextUser, targetId: subAgentEntity.ID, inputData, payloadAtStart: previousDecision.newPayload, parentId: parentStepId });
2218
2474
  this.incrementExecutionCount(subAgentEntity.ID);
2219
2475
  try {
2220
- let downstreamPaths = ['*'];
2221
- let upstreamPaths = ['*'];
2222
- try {
2223
- if (subAgentEntity.PayloadDownstreamPaths) {
2224
- downstreamPaths = JSON.parse(subAgentEntity.PayloadDownstreamPaths);
2225
- }
2226
- if (subAgentEntity.PayloadUpstreamPaths) {
2227
- upstreamPaths = JSON.parse(subAgentEntity.PayloadUpstreamPaths);
2228
- }
2476
+ const { downstreamPaths, upstreamPaths } = this.computeUpstreamDownstreamPaths(params, subAgentEntity, subAgentRequest);
2477
+ let scopedPayload = null;
2478
+ if (!subAgentPayloadOverride) {
2479
+ scopedPayload = await this.computeChildSubAgentPayload(params, subAgentEntity, downstreamPaths, subAgentRequest, previousDecision);
2229
2480
  }
2230
- catch (parseError) {
2231
- this.logError(`Failed to parse payload paths for sub-agent ${subAgentRequest.name}: ${parseError.message}`, {
2232
- category: 'SubAgentExecution',
2233
- metadata: {
2234
- agentName: params.agent.Name,
2235
- subAgentName: subAgentRequest.name,
2236
- subAgentId: subAgentEntity.ID,
2237
- downstreamPaths: subAgentEntity.PayloadDownstreamPaths,
2238
- upstreamPaths: subAgentEntity.PayloadUpstreamPaths
2239
- }
2240
- });
2241
- }
2242
- let downstreamPayload = this._payloadManager.extractDownstreamPayload(subAgentRequest.name, previousDecision.newPayload, downstreamPaths);
2243
- let scopedPayload = downstreamPayload;
2244
- if (subAgentEntity.PayloadScope) {
2245
- scopedPayload = this._payloadManager.applyPayloadScope(downstreamPayload, subAgentEntity.PayloadScope);
2246
- if (scopedPayload === null) {
2247
- const errorMessage = `Critical: Failed to extract payload scope '${subAgentEntity.PayloadScope}' for sub-agent '${subAgentRequest.name}'. The specified path does not exist in the payload.`;
2248
- this.logError(errorMessage, {
2249
- category: 'SubAgentExecution',
2250
- metadata: {
2251
- agentName: params.agent.Name,
2252
- subAgentName: subAgentRequest.name,
2253
- payloadScope: subAgentEntity.PayloadScope,
2254
- availableKeys: Object.keys(downstreamPayload || {})
2255
- }
2256
- });
2257
- throw new Error(errorMessage);
2258
- }
2481
+ else {
2482
+ scopedPayload = subAgentPayloadOverride;
2259
2483
  }
2260
2484
  stepEntity.PayloadAtStart = JSON.stringify(previousDecision.newPayload);
2261
2485
  const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity, scopedPayload, undefined);
@@ -2404,7 +2628,7 @@ The context is now within limits. Please retry your request with the recovered c
2404
2628
  };
2405
2629
  }
2406
2630
  }
2407
- async processSubAgentStep(params, previousDecision) {
2631
+ async processSubAgentStep(params, previousDecision, parentStepId, subAgentPayloadOverride) {
2408
2632
  const subAgentRequest = previousDecision.subAgent;
2409
2633
  const name = subAgentRequest?.name;
2410
2634
  if (!name) {
@@ -2420,7 +2644,7 @@ The context is now within limits. Please retry your request with the recovered c
2420
2644
  a.Status === 'Active');
2421
2645
  const childAgent = childAgents.find(a => a.Name.trim().toLowerCase() === name.trim().toLowerCase());
2422
2646
  if (childAgent) {
2423
- return await this.executeChildSubAgentStep(params, previousDecision);
2647
+ return await this.executeChildSubAgentStep(params, previousDecision, parentStepId, subAgentPayloadOverride);
2424
2648
  }
2425
2649
  const activeRelationships = aiengine_1.AIEngine.Instance.AgentRelationships.filter(ar => ar.AgentID === params.agent.ID &&
2426
2650
  ar.Status === 'Active');
@@ -2428,7 +2652,7 @@ The context is now within limits. Please retry your request with the recovered c
2428
2652
  const relatedAgent = aiengine_1.AIEngine.Instance.Agents.find(a => a.ID === relationship.SubAgentID &&
2429
2653
  a.Status === 'Active');
2430
2654
  if (relatedAgent && relatedAgent.Name.trim().toLowerCase() === name.trim().toLowerCase()) {
2431
- return await this.executeRelatedSubAgentStep(params, previousDecision, relatedAgent, relationship);
2655
+ return await this.executeRelatedSubAgentStep(params, previousDecision, relatedAgent, relationship, parentStepId, subAgentPayloadOverride);
2432
2656
  }
2433
2657
  }
2434
2658
  this.logError(`Sub-agent '${name}' not found or not active for agent '${params.agent.Name}'`, {
@@ -2443,7 +2667,7 @@ The context is now within limits. Please retry your request with the recovered c
2443
2667
  newPayload: previousDecision?.newPayload
2444
2668
  };
2445
2669
  }
2446
- async executeRelatedSubAgentStep(params, previousDecision, subAgentEntity, relationship) {
2670
+ async executeRelatedSubAgentStep(params, previousDecision, subAgentEntity, relationship, parentStepId, subAgentPayloadOverride) {
2447
2671
  const subAgentRequest = previousDecision.subAgent;
2448
2672
  if (params.cancellationToken?.aborted) {
2449
2673
  throw new Error('Cancelled before related sub-agent execution');
@@ -2478,13 +2702,14 @@ The context is now within limits. Please retry your request with the recovered c
2478
2702
  contextUser: params.contextUser,
2479
2703
  targetId: subAgentEntity.ID,
2480
2704
  inputData,
2481
- payloadAtStart: previousDecision.newPayload
2705
+ payloadAtStart: previousDecision.newPayload,
2706
+ parentId: parentStepId
2482
2707
  });
2483
2708
  this.incrementExecutionCount(subAgentEntity.ID);
2484
2709
  try {
2485
2710
  stepEntity.PayloadAtStart = JSON.stringify(previousDecision.newPayload);
2486
- let initialSubAgentPayload = undefined;
2487
- if (relationship.SubAgentInputMapping) {
2711
+ let initialSubAgentPayload = subAgentPayloadOverride;
2712
+ if (!initialSubAgentPayload && relationship.SubAgentInputMapping) {
2488
2713
  const mapped = this.applySubAgentInputMapping(previousDecision.newPayload, relationship.SubAgentInputMapping);
2489
2714
  if (mapped && Object.keys(mapped).length > 0) {
2490
2715
  initialSubAgentPayload = mapped;
@@ -2607,12 +2832,13 @@ The context is now within limits. Please retry your request with the recovered c
2607
2832
  let current = updateObj;
2608
2833
  for (let i = 0; i < pathParts.length - 1; i++) {
2609
2834
  const part = pathParts[i];
2610
- if (!(part in current)) {
2611
- current[part] = {};
2835
+ const cleanPart = part.endsWith('[]') ? part.slice(0, -2) : part;
2836
+ if (!(cleanPart in current)) {
2837
+ current[cleanPart] = {};
2612
2838
  }
2613
- current = current[part];
2839
+ current = current[cleanPart];
2614
2840
  }
2615
- current[pathParts[pathParts.length - 1]] = value;
2841
+ this.setMappedValue(current, pathParts[pathParts.length - 1], value);
2616
2842
  }
2617
2843
  }
2618
2844
  if (Object.keys(updateObj).length === 0) {
@@ -2627,6 +2853,23 @@ The context is now within limits. Please retry your request with the recovered c
2627
2853
  return null;
2628
2854
  }
2629
2855
  }
2856
+ setMappedValue(target, key, value) {
2857
+ const isArrayAppend = key.endsWith('[]');
2858
+ const actualKey = isArrayAppend ? key.slice(0, -2) : key;
2859
+ if (isArrayAppend) {
2860
+ if (!(actualKey in target)) {
2861
+ target[actualKey] = [];
2862
+ }
2863
+ if (!Array.isArray(target[actualKey])) {
2864
+ throw new Error(`Cannot append to '${actualKey}': target is not an array. ` +
2865
+ `Use '${actualKey}' without [] suffix for property update.`);
2866
+ }
2867
+ target[actualKey].push(value);
2868
+ }
2869
+ else {
2870
+ target[actualKey] = value;
2871
+ }
2872
+ }
2630
2873
  applySubAgentInputMapping(parentPayload, mappingConfig) {
2631
2874
  try {
2632
2875
  const mapping = JSON.parse(mappingConfig);
@@ -2784,7 +3027,7 @@ The context is now within limits. Please retry your request with the recovered c
2784
3027
  const agentActions = aiengine_1.AIEngine.Instance.AgentActions.filter(aa => aa.AgentID === params.agent.ID);
2785
3028
  try {
2786
3029
  const currentPayload = previousDecision?.newPayload || previousDecision?.previousPayload || params.payload;
2787
- await this.AgentTypeInstance.PreProcessActionStep(actions, currentPayload, this.AgentTypeState, previousDecision);
3030
+ await this.AgentTypeInstance.PreProcessActionStep(actions, currentPayload, this.AgentTypeState, previousDecision, params);
2788
3031
  }
2789
3032
  catch (error) {
2790
3033
  (0, core_1.LogError)(`Error in PreProcessActionStep: ${error.message}`);
@@ -2793,7 +3036,7 @@ The context is now within limits. Please retry your request with the recovered c
2793
3036
  const baseStepNumber = (this._agentRun.Steps?.length || 0) + 1;
2794
3037
  let lastStep = undefined;
2795
3038
  const actionPromises = actions.map(async (aa) => {
2796
- const actionEntity = actionEngine.Actions.find(a => a.Name === aa.name && agentActions.some(aa => aa.ActionID === a.ID));
3039
+ const actionEntity = actionEngine.Actions.find(a => a.Name === aa.name && agentActions.some(agentAction => agentAction.ActionID === a.ID));
2797
3040
  if (!actionEntity) {
2798
3041
  throw new Error(`Action "${aa.name}" Not Found for Agent "${params.agent.Name}"`);
2799
3042
  }
@@ -2892,7 +3135,7 @@ The context is now within limits. Please retry your request with the recovered c
2892
3135
  if (payloadChangeRequest) {
2893
3136
  const allowedPaths = params.agent.PayloadSelfWritePaths
2894
3137
  ? JSON.parse(params.agent.PayloadSelfWritePaths)
2895
- : undefined;
3138
+ : this.getDefaultPayloadSelfWritePaths();
2896
3139
  const changeResult = this._payloadManager.applyAgentChangeRequest(currentPayload, payloadChangeRequest, {
2897
3140
  validateChanges: true,
2898
3141
  logChanges: true,
@@ -3147,10 +3390,17 @@ The context is now within limits. Please retry your request with the recovered c
3147
3390
  async executeSingleForEachIteration(forEach, item, index, currentPayload, parentStepId, params, config) {
3148
3391
  try {
3149
3392
  const beforeHook = this.AgentTypeInstance.BeforeLoopIteration?.({ item, itemVariable: forEach.itemVariable, index, payload: currentPayload, loopType: 'ForEach', actionParams: forEach.action?.params || {} });
3150
- const resolvedParams = beforeHook?.actionParams || forEach.action?.params || {};
3393
+ let resolvedParams = beforeHook?.actionParams || forEach.action?.params || {};
3151
3394
  let result;
3152
3395
  if (forEach.action) {
3153
3396
  const matchedAction = this.findAgentActionForLoop(forEach.action.name, params.agent.ID, params.agent.Name, params);
3397
+ const context = {
3398
+ item,
3399
+ index,
3400
+ payload: currentPayload,
3401
+ data: params.data
3402
+ };
3403
+ resolvedParams = this.resolveTemplates(resolvedParams, context, forEach.itemVariable);
3154
3404
  const resolvedAction = {
3155
3405
  name: matchedAction.Action,
3156
3406
  params: resolvedParams
@@ -3160,7 +3410,7 @@ The context is now within limits. Please retry your request with the recovered c
3160
3410
  }
3161
3411
  else if (forEach.subAgent) {
3162
3412
  const subAgentStep = { step: 'Sub-Agent', subAgent: forEach.subAgent, newPayload: currentPayload, previousPayload: currentPayload };
3163
- result = await this.processSubAgentStep(params, subAgentStep);
3413
+ result = await this.processSubAgentStep(params, subAgentStep, parentStepId, item);
3164
3414
  }
3165
3415
  else {
3166
3416
  throw new Error('ForEach missing action/subAgent');
@@ -3283,10 +3533,17 @@ The context is now within limits. Please retry your request with the recovered c
3283
3533
  async executeSingleWhileIteration(whileOp, attemptContext, index, currentPayload, parentStepId, params, config) {
3284
3534
  try {
3285
3535
  const beforeHook = this.AgentTypeInstance.BeforeLoopIteration?.({ item: attemptContext, index, itemVariable: whileOp.itemVariable, payload: currentPayload, loopType: 'While', actionParams: whileOp.action?.params || {} });
3286
- const resolvedParams = beforeHook?.actionParams || whileOp.action?.params || {};
3536
+ let resolvedParams = beforeHook?.actionParams || whileOp.action?.params || {};
3287
3537
  let result;
3288
3538
  if (whileOp.action) {
3289
3539
  const matchedAction = this.findAgentActionForLoop(whileOp.action.name, params.agent.ID, params.agent.Name, params);
3540
+ const context = {
3541
+ item: attemptContext,
3542
+ index,
3543
+ payload: currentPayload,
3544
+ data: params.data
3545
+ };
3546
+ resolvedParams = this.resolveTemplates(resolvedParams, context, whileOp.itemVariable || 'item');
3290
3547
  const resolvedAction = {
3291
3548
  name: matchedAction.Action,
3292
3549
  params: resolvedParams
@@ -3296,7 +3553,7 @@ The context is now within limits. Please retry your request with the recovered c
3296
3553
  }
3297
3554
  else if (whileOp.subAgent) {
3298
3555
  const subAgentStep = { step: 'Sub-Agent', subAgent: whileOp.subAgent, newPayload: currentPayload, previousPayload: currentPayload };
3299
- result = await this.processSubAgentStep(params, subAgentStep);
3556
+ result = await this.processSubAgentStep(params, subAgentStep, parentStepId, attemptContext);
3300
3557
  }
3301
3558
  else {
3302
3559
  throw new Error('While missing action/subAgent');
@@ -3739,6 +3996,79 @@ The context is now within limits. Please retry your request with the recovered c
3739
3996
  console.log(`[Turn ${currentTurn}] Expanded message at index ${messageIndex}`);
3740
3997
  }
3741
3998
  }
3999
+ resolveTemplates(obj, context, itemVariable) {
4000
+ const result = {};
4001
+ for (const [key, value] of Object.entries(obj)) {
4002
+ if (typeof value === 'string') {
4003
+ result[key] = this.resolveValueFromContext(value, context, itemVariable);
4004
+ }
4005
+ else if (Array.isArray(value)) {
4006
+ result[key] = value.map(v => typeof v === 'string' ? this.resolveValueFromContext(v, context, itemVariable) : v);
4007
+ }
4008
+ else if (typeof value === 'object' && value !== null) {
4009
+ result[key] = this.resolveTemplates(value, context, itemVariable);
4010
+ }
4011
+ else {
4012
+ result[key] = value;
4013
+ }
4014
+ }
4015
+ return result;
4016
+ }
4017
+ resolveValueFromContext(value, context, itemVariable) {
4018
+ const trimmedValue = value.trim();
4019
+ if (trimmedValue.startsWith('{{') && trimmedValue.endsWith('}}')) {
4020
+ value = trimmedValue.substring(2, trimmedValue.length - 2).trim();
4021
+ }
4022
+ const ivToLower = itemVariable?.trim().toLowerCase();
4023
+ if (value?.toLowerCase().startsWith(`${ivToLower}.`)) {
4024
+ const path = value.substring(ivToLower.length + 1);
4025
+ return this.getValueFromPath(context.item, path);
4026
+ }
4027
+ for (const [varName, varValue] of Object.entries(context)) {
4028
+ if (value === varName) {
4029
+ return varValue;
4030
+ }
4031
+ if (value?.trim().toLowerCase().startsWith(`${varName}.`)) {
4032
+ const path = value.substring(varName.length + 1);
4033
+ return this.getValueFromPath(varValue, path);
4034
+ }
4035
+ }
4036
+ return value;
4037
+ }
4038
+ getValueFromPath(obj, path) {
4039
+ const parts = path.split('.');
4040
+ let current = obj;
4041
+ for (const part of parts) {
4042
+ if (!part)
4043
+ continue;
4044
+ const arrayMatch = part.match(/^([^[]+)\[(\d+)\]$/);
4045
+ if (arrayMatch) {
4046
+ const arrayName = arrayMatch[1];
4047
+ const index = parseInt(arrayMatch[2], 10);
4048
+ if (current && typeof current === 'object' && arrayName in current) {
4049
+ current = current[arrayName];
4050
+ if (Array.isArray(current) && index >= 0 && index < current.length) {
4051
+ current = current[index];
4052
+ }
4053
+ else {
4054
+ return undefined;
4055
+ }
4056
+ }
4057
+ else {
4058
+ return undefined;
4059
+ }
4060
+ }
4061
+ else {
4062
+ if (current && typeof current === 'object' && part in current) {
4063
+ current = current[part];
4064
+ }
4065
+ else {
4066
+ return undefined;
4067
+ }
4068
+ }
4069
+ }
4070
+ return current;
4071
+ }
3742
4072
  }
3743
4073
  exports.BaseAgent = BaseAgent;
3744
4074
  BaseAgent.MAX_VALIDATION_RETRIES = 10;