@memberjunction/ai-agents 2.107.0 → 2.109.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 +450 -0
- package/dist/AgentDataPreloader.d.ts +25 -0
- package/dist/AgentDataPreloader.d.ts.map +1 -0
- package/dist/AgentDataPreloader.js +264 -0
- package/dist/AgentDataPreloader.js.map +1 -0
- package/dist/agent-types/loop-agent-response-type.d.ts +2 -1
- package/dist/agent-types/loop-agent-response-type.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-type.js +4 -2
- package/dist/agent-types/loop-agent-type.js.map +1 -1
- package/dist/base-agent.d.ts +33 -4
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +673 -36
- package/dist/base-agent.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/base-agent.js
CHANGED
|
@@ -34,6 +34,7 @@ const ai_engine_base_1 = require("@memberjunction/ai-engine-base");
|
|
|
34
34
|
const ai_core_plus_1 = require("@memberjunction/ai-core-plus");
|
|
35
35
|
const AgentRunner_1 = require("./AgentRunner");
|
|
36
36
|
const PayloadManager_1 = require("./PayloadManager");
|
|
37
|
+
const AgentDataPreloader_1 = require("./AgentDataPreloader");
|
|
37
38
|
const _ = __importStar(require("lodash"));
|
|
38
39
|
class BaseAgent {
|
|
39
40
|
constructor() {
|
|
@@ -49,6 +50,7 @@ class BaseAgent {
|
|
|
49
50
|
this._subAgentRuns = [];
|
|
50
51
|
this._payloadManager = new PayloadManager_1.PayloadManager();
|
|
51
52
|
this._validationRetryCount = 0;
|
|
53
|
+
this._contextRecoveryAttempted = false;
|
|
52
54
|
}
|
|
53
55
|
get AgentTypeState() {
|
|
54
56
|
return this._agentTypeState;
|
|
@@ -132,6 +134,53 @@ class BaseAgent {
|
|
|
132
134
|
this._agentTypeInstance = await base_agent_type_1.BaseAgentType.GetAgentTypeInstance(config.agentType);
|
|
133
135
|
this._agentTypeState = await this._agentTypeInstance.InitializeAgentTypeState(params);
|
|
134
136
|
}
|
|
137
|
+
async preloadAgentData(params) {
|
|
138
|
+
if (params.disableDataPreloading === true) {
|
|
139
|
+
this.logStatus(`⏭️ Data preloading disabled for agent '${params.agent.Name}'`, true, params);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const preloadedResult = await AgentDataPreloader_1.AgentDataPreloader.Instance.PreloadAgentData(params.agent.ID, params.contextUser, this._agentRun?.ID);
|
|
144
|
+
const totalSources = Object.keys(preloadedResult.data).length +
|
|
145
|
+
Object.keys(preloadedResult.context).length +
|
|
146
|
+
Object.keys(preloadedResult.payload).length;
|
|
147
|
+
if (totalSources > 0) {
|
|
148
|
+
const destinations = [];
|
|
149
|
+
if (Object.keys(preloadedResult.data).length > 0) {
|
|
150
|
+
destinations.push(`data(${Object.keys(preloadedResult.data).length})`);
|
|
151
|
+
}
|
|
152
|
+
if (Object.keys(preloadedResult.context).length > 0) {
|
|
153
|
+
destinations.push(`context(${Object.keys(preloadedResult.context).length})`);
|
|
154
|
+
}
|
|
155
|
+
if (Object.keys(preloadedResult.payload).length > 0) {
|
|
156
|
+
destinations.push(`payload(${Object.keys(preloadedResult.payload).length})`);
|
|
157
|
+
}
|
|
158
|
+
this.logStatus(`📊 Preloaded ${totalSources} data source(s) for agent '${params.agent.Name}': ${destinations.join(', ')}`, true, params);
|
|
159
|
+
params.data = {
|
|
160
|
+
...preloadedResult.data,
|
|
161
|
+
...params.data
|
|
162
|
+
};
|
|
163
|
+
params.context = {
|
|
164
|
+
...preloadedResult.context,
|
|
165
|
+
...params.context
|
|
166
|
+
};
|
|
167
|
+
params.payload = {
|
|
168
|
+
...preloadedResult.payload,
|
|
169
|
+
...params.payload
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
this.logStatus(`📭 No data sources configured for agent '${params.agent.Name}'`, true, params);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
this.logError(`Failed to preload data for agent '${params.agent.Name}': ${error.message}`, {
|
|
178
|
+
agent: params.agent,
|
|
179
|
+
category: 'DataPreloading',
|
|
180
|
+
severity: 'warning'
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
135
184
|
async Execute(params) {
|
|
136
185
|
try {
|
|
137
186
|
this.logStatus(`🤖 Starting execution of agent '${params.agent.Name}'`, true, params);
|
|
@@ -158,6 +207,8 @@ class BaseAgent {
|
|
|
158
207
|
await this.initializeAgentRun(wrappedParams);
|
|
159
208
|
this._validationRetryCount = 0;
|
|
160
209
|
this._generalValidationRetryCount = 0;
|
|
210
|
+
this._contextRecoveryAttempted = false;
|
|
211
|
+
this._messageLifecycleCallback = params.onMessageLifecycle;
|
|
161
212
|
await this.initializeEngines(params.contextUser);
|
|
162
213
|
if (params.cancellationToken?.aborted) {
|
|
163
214
|
return await this.createCancelledResult('Cancelled during initialization', params.contextUser);
|
|
@@ -183,6 +234,7 @@ class BaseAgent {
|
|
|
183
234
|
});
|
|
184
235
|
return await this.createFailureResult(config.errorMessage || 'Failed to load agent configuration', params.contextUser);
|
|
185
236
|
}
|
|
237
|
+
await this.preloadAgentData(wrappedParams);
|
|
186
238
|
await this.initializeAgentType(wrappedParams, config);
|
|
187
239
|
this.logStatus(`🚀 Executing agent '${params.agent.Name}' internal logic`, true, params);
|
|
188
240
|
const executionResult = await this.executeAgentInternal(wrappedParams, config);
|
|
@@ -219,6 +271,7 @@ class BaseAgent {
|
|
|
219
271
|
if (params.cancellationToken?.aborted) {
|
|
220
272
|
throw new Error('Cancelled during execution');
|
|
221
273
|
}
|
|
274
|
+
await this.pruneAndCompactExpiredMessages(params, stepCount);
|
|
222
275
|
this.logStatus(`🔄 Executing step ${stepCount + 1} for agent '${params.agent.Name}'`, true, params);
|
|
223
276
|
const nextStep = await this.executeNextStep(params, config, currentNextStep);
|
|
224
277
|
stepCount++;
|
|
@@ -897,6 +950,163 @@ class BaseAgent {
|
|
|
897
950
|
}
|
|
898
951
|
return { exceeded: false };
|
|
899
952
|
}
|
|
953
|
+
isFatalPromptError(promptResult) {
|
|
954
|
+
if (!promptResult?.chatResult?.errorInfo) {
|
|
955
|
+
return false;
|
|
956
|
+
}
|
|
957
|
+
const errorInfo = promptResult.chatResult.errorInfo;
|
|
958
|
+
if (errorInfo.severity === 'Fatal') {
|
|
959
|
+
return true;
|
|
960
|
+
}
|
|
961
|
+
const fatalErrorTypes = [
|
|
962
|
+
'ContextLengthExceeded',
|
|
963
|
+
'Authentication',
|
|
964
|
+
'InvalidRequest'
|
|
965
|
+
];
|
|
966
|
+
return fatalErrorTypes.includes(errorInfo.errorType);
|
|
967
|
+
}
|
|
968
|
+
contentToString(content) {
|
|
969
|
+
if (typeof content === 'string') {
|
|
970
|
+
return content;
|
|
971
|
+
}
|
|
972
|
+
return content.map((block) => {
|
|
973
|
+
if (block.type === 'text') {
|
|
974
|
+
return block.content;
|
|
975
|
+
}
|
|
976
|
+
return `[${block.type}: ${block.content}]`;
|
|
977
|
+
}).join('\n');
|
|
978
|
+
}
|
|
979
|
+
smartTrimContent(content, maxLength = 1000) {
|
|
980
|
+
const originalLength = content.length;
|
|
981
|
+
try {
|
|
982
|
+
const data = JSON.parse(content);
|
|
983
|
+
if (Array.isArray(data)) {
|
|
984
|
+
const itemsToKeep = 10;
|
|
985
|
+
if (data.length > itemsToKeep) {
|
|
986
|
+
const truncated = data.slice(0, itemsToKeep);
|
|
987
|
+
const trimmed = JSON.stringify(truncated, null, 2) +
|
|
988
|
+
`\n\n... (${(data.length - itemsToKeep).toLocaleString()} more items truncated due to context length)`;
|
|
989
|
+
return {
|
|
990
|
+
trimmed,
|
|
991
|
+
strategy: 'JSON array truncation',
|
|
992
|
+
originalLength
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
else if (typeof data === 'object' && data !== null) {
|
|
997
|
+
const truncated = {};
|
|
998
|
+
let fieldCount = 0;
|
|
999
|
+
const maxFields = 20;
|
|
1000
|
+
for (const [key, value] of Object.entries(data)) {
|
|
1001
|
+
if (fieldCount >= maxFields) {
|
|
1002
|
+
truncated['...'] = `(${Object.keys(data).length - maxFields} more fields truncated)`;
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1005
|
+
if (typeof value === 'string' && value.length > 200) {
|
|
1006
|
+
truncated[key] = value.substring(0, 200) + '... (truncated)';
|
|
1007
|
+
}
|
|
1008
|
+
else if (Array.isArray(value) && value.length > 5) {
|
|
1009
|
+
truncated[key] = [...value.slice(0, 5), `... (${value.length - 5} more items)`];
|
|
1010
|
+
}
|
|
1011
|
+
else {
|
|
1012
|
+
truncated[key] = value;
|
|
1013
|
+
}
|
|
1014
|
+
fieldCount++;
|
|
1015
|
+
}
|
|
1016
|
+
return {
|
|
1017
|
+
trimmed: JSON.stringify(truncated, null, 2),
|
|
1018
|
+
strategy: 'JSON object field truncation',
|
|
1019
|
+
originalLength
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
catch {
|
|
1024
|
+
}
|
|
1025
|
+
if (content.includes('\n')) {
|
|
1026
|
+
const lines = content.split('\n');
|
|
1027
|
+
const firstLine = lines[0];
|
|
1028
|
+
if (firstLine.includes(',') && lines.length > 1) {
|
|
1029
|
+
const rowsToKeep = 10;
|
|
1030
|
+
if (lines.length > rowsToKeep + 1) {
|
|
1031
|
+
const header = lines[0];
|
|
1032
|
+
const dataRows = lines.slice(1, rowsToKeep + 1);
|
|
1033
|
+
const trimmed = [header, ...dataRows].join('\n') +
|
|
1034
|
+
`\n... (${(lines.length - rowsToKeep - 1).toLocaleString()} more rows truncated due to context length)`;
|
|
1035
|
+
return {
|
|
1036
|
+
trimmed,
|
|
1037
|
+
strategy: 'CSV row truncation',
|
|
1038
|
+
originalLength
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
if (content.length > maxLength) {
|
|
1044
|
+
return {
|
|
1045
|
+
trimmed: content.substring(0, maxLength) + '\n\n... (truncated due to context length)',
|
|
1046
|
+
strategy: 'character truncation',
|
|
1047
|
+
originalLength
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
return {
|
|
1051
|
+
trimmed: content,
|
|
1052
|
+
strategy: 'no truncation needed',
|
|
1053
|
+
originalLength
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
async attemptContextRecovery(params, payload, errorMessage) {
|
|
1057
|
+
this.logStatus(`⚠️ Context length exceeded - attempting recovery by trimming conversation messages`, true, params);
|
|
1058
|
+
const messages = params.conversationMessages;
|
|
1059
|
+
let lastUserMessageIndex = -1;
|
|
1060
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1061
|
+
if (messages[i].role === 'user') {
|
|
1062
|
+
lastUserMessageIndex = i;
|
|
1063
|
+
break;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
if (lastUserMessageIndex === -1) {
|
|
1067
|
+
this.logStatus(`❌ Context recovery failed: No trimmable user messages found`, true, params);
|
|
1068
|
+
return {
|
|
1069
|
+
errorMessage: `Context overflow with no trimmable messages: ${errorMessage}`,
|
|
1070
|
+
step: 'Failed',
|
|
1071
|
+
terminate: true,
|
|
1072
|
+
previousPayload: payload,
|
|
1073
|
+
newPayload: payload
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
const originalMessage = messages[lastUserMessageIndex];
|
|
1077
|
+
const contentString = this.contentToString(originalMessage.content);
|
|
1078
|
+
const trimResult = this.smartTrimContent(contentString, 1000);
|
|
1079
|
+
this.logStatus(`✂️ Trimmed message from ${trimResult.originalLength.toLocaleString()} to ${trimResult.trimmed.length.toLocaleString()} characters using ${trimResult.strategy}`, true, params);
|
|
1080
|
+
messages[lastUserMessageIndex] = {
|
|
1081
|
+
role: 'user',
|
|
1082
|
+
content: `⚠️ CONTEXT OVERFLOW RECOVERY ⚠️
|
|
1083
|
+
|
|
1084
|
+
The previous step returned a result that exceeded the context window (${(trimResult.originalLength - trimResult.trimmed.length).toLocaleString()} characters truncated).
|
|
1085
|
+
|
|
1086
|
+
Here is a PARTIAL result from the previous action:
|
|
1087
|
+
---
|
|
1088
|
+
${trimResult.trimmed}
|
|
1089
|
+
---
|
|
1090
|
+
|
|
1091
|
+
❗ THE ABOVE IS INCOMPLETE - the full result was too large for the context window.
|
|
1092
|
+
|
|
1093
|
+
RECOMMENDED ACTIONS:
|
|
1094
|
+
1. Use a different action with more specific filters to get smaller result sets
|
|
1095
|
+
2. Request data in batches or pages instead of all at once
|
|
1096
|
+
3. Ask the user to clarify scope to narrow the query
|
|
1097
|
+
4. If you need the full data, acknowledge the limitation and ask the user how to proceed
|
|
1098
|
+
|
|
1099
|
+
Please choose an alternative approach to complete your task.`
|
|
1100
|
+
};
|
|
1101
|
+
return {
|
|
1102
|
+
step: 'Retry',
|
|
1103
|
+
retryReason: 'Context length recovery - previous result too large',
|
|
1104
|
+
retryInstructions: 'The previous action result exceeded context limits. Use more specific filters or request data in smaller batches.',
|
|
1105
|
+
terminate: false,
|
|
1106
|
+
previousPayload: payload,
|
|
1107
|
+
newPayload: payload
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
900
1110
|
async processNextStep(nextStep, params, agentType, promptResult, currentPayload, currentStep) {
|
|
901
1111
|
const validatedNextStep = await this.validateNextStep(params, nextStep, currentPayload, this._agentRun, currentStep);
|
|
902
1112
|
const guardrailCheckedStep = await this.checkExecutionGuardrails(params, validatedNextStep, currentPayload, this._agentRun, currentStep);
|
|
@@ -1006,16 +1216,18 @@ class BaseAgent {
|
|
|
1006
1216
|
throw new Error(`Error executing actions: ${error.message}`);
|
|
1007
1217
|
}
|
|
1008
1218
|
}
|
|
1009
|
-
async ExecuteSubAgent(params, subAgentRequest, subAgent, stepEntity, payload) {
|
|
1219
|
+
async ExecuteSubAgent(params, subAgentRequest, subAgent, stepEntity, payload, contextMessage) {
|
|
1010
1220
|
try {
|
|
1011
1221
|
this.logStatus(`🤖 Executing sub-agent '${subAgentRequest.name}'`, true, params);
|
|
1012
1222
|
const runner = new AgentRunner_1.AgentRunner();
|
|
1013
|
-
const subAgentMessages = [
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1223
|
+
const subAgentMessages = [];
|
|
1224
|
+
if (contextMessage) {
|
|
1225
|
+
subAgentMessages.push(contextMessage);
|
|
1226
|
+
}
|
|
1227
|
+
subAgentMessages.push({
|
|
1228
|
+
role: 'user',
|
|
1229
|
+
content: subAgentRequest.message
|
|
1230
|
+
});
|
|
1019
1231
|
this.logStatus(`📨 Sub-agent message: "${subAgentRequest.message}"`, true, params);
|
|
1020
1232
|
if (subAgentRequest.templateParameters) {
|
|
1021
1233
|
this.logStatus(`📎 Template parameters: ${JSON.stringify(subAgentRequest.templateParameters)}`, true, params);
|
|
@@ -1134,6 +1346,25 @@ class BaseAgent {
|
|
|
1134
1346
|
ValueType: param.ValueType
|
|
1135
1347
|
};
|
|
1136
1348
|
}
|
|
1349
|
+
formatParamValueForMessage(value, maxLength = 100) {
|
|
1350
|
+
if (value === null || value === undefined) {
|
|
1351
|
+
return 'null';
|
|
1352
|
+
}
|
|
1353
|
+
let stringValue;
|
|
1354
|
+
if (typeof value === 'string') {
|
|
1355
|
+
stringValue = value;
|
|
1356
|
+
}
|
|
1357
|
+
else if (typeof value === 'object') {
|
|
1358
|
+
stringValue = JSON.stringify(value);
|
|
1359
|
+
}
|
|
1360
|
+
else {
|
|
1361
|
+
stringValue = String(value);
|
|
1362
|
+
}
|
|
1363
|
+
if (stringValue.length > maxLength) {
|
|
1364
|
+
return `\`${stringValue.substring(0, maxLength)}...\``;
|
|
1365
|
+
}
|
|
1366
|
+
return `\`${stringValue}\``;
|
|
1367
|
+
}
|
|
1137
1368
|
getAgentTypeName(typeID) {
|
|
1138
1369
|
const agentType = aiengine_1.AIEngine.Instance.AgentTypes.find(at => at.ID === typeID);
|
|
1139
1370
|
return agentType?.Name || 'Unknown';
|
|
@@ -1364,6 +1595,10 @@ class BaseAgent {
|
|
|
1364
1595
|
}
|
|
1365
1596
|
switch (previousDecision.step) {
|
|
1366
1597
|
case 'Retry':
|
|
1598
|
+
if (previousDecision.messageIndex !== undefined) {
|
|
1599
|
+
const currentStepCount = this._agentRun?.Steps?.length || 0;
|
|
1600
|
+
this.executeExpandMessageStep(previousDecision, params, currentStepCount);
|
|
1601
|
+
}
|
|
1367
1602
|
return await this.executePromptStep(params, config, previousDecision);
|
|
1368
1603
|
case 'Sub-Agent':
|
|
1369
1604
|
return await this.processSubAgentStep(params, previousDecision);
|
|
@@ -1466,6 +1701,25 @@ class BaseAgent {
|
|
|
1466
1701
|
stepEntity.TargetLogID = promptResult.promptRun.ID;
|
|
1467
1702
|
stepEntity.PromptRun = promptResult.promptRun;
|
|
1468
1703
|
}
|
|
1704
|
+
if (!promptResult.success) {
|
|
1705
|
+
await this.finalizeStepEntity(stepEntity, false, promptResult.errorMessage);
|
|
1706
|
+
const isFatal = this.isFatalPromptError(promptResult);
|
|
1707
|
+
const isContextOverflow = isFatal &&
|
|
1708
|
+
promptResult.chatResult?.errorInfo?.errorType === 'ContextLengthExceeded';
|
|
1709
|
+
if (isContextOverflow && !this._contextRecoveryAttempted) {
|
|
1710
|
+
this._contextRecoveryAttempted = true;
|
|
1711
|
+
this.logStatus(`⚠️ Context length exceeded - attempting recovery by trimming conversation`, true, params);
|
|
1712
|
+
return await this.attemptContextRecovery(params, payload, promptResult.errorMessage || 'Context length exceeded');
|
|
1713
|
+
}
|
|
1714
|
+
this.logStatus(`❌ Prompt execution failed: ${promptResult.errorMessage} (fatal: ${isFatal})`, true, params);
|
|
1715
|
+
return {
|
|
1716
|
+
errorMessage: promptResult.errorMessage || 'Prompt execution failed',
|
|
1717
|
+
step: 'Failed',
|
|
1718
|
+
terminate: isFatal,
|
|
1719
|
+
previousPayload: payload,
|
|
1720
|
+
newPayload: payload
|
|
1721
|
+
};
|
|
1722
|
+
}
|
|
1469
1723
|
if (params.cancellationToken?.aborted) {
|
|
1470
1724
|
await this.finalizeStepEntity(stepEntity, false, 'Cancelled during prompt execution');
|
|
1471
1725
|
const cancelledResult = await this.createCancelledResult('Cancelled during prompt execution', params.contextUser);
|
|
@@ -1631,7 +1885,7 @@ class BaseAgent {
|
|
|
1631
1885
|
}
|
|
1632
1886
|
}
|
|
1633
1887
|
stepEntity.PayloadAtStart = JSON.stringify(previousDecision.newPayload);
|
|
1634
|
-
const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity, scopedPayload);
|
|
1888
|
+
const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity, scopedPayload, undefined);
|
|
1635
1889
|
let mergedPayload = previousDecision.newPayload;
|
|
1636
1890
|
let currentStepPayloadChangeResult = undefined;
|
|
1637
1891
|
if (subAgentResult.success) {
|
|
@@ -1843,12 +2097,34 @@ class BaseAgent {
|
|
|
1843
2097
|
this.incrementExecutionCount(subAgentEntity.ID);
|
|
1844
2098
|
try {
|
|
1845
2099
|
stepEntity.PayloadAtStart = JSON.stringify(previousDecision.newPayload);
|
|
1846
|
-
|
|
2100
|
+
let initialSubAgentPayload = undefined;
|
|
2101
|
+
if (relationship.SubAgentInputMapping) {
|
|
2102
|
+
const mapped = this.applySubAgentInputMapping(previousDecision.newPayload, relationship.SubAgentInputMapping);
|
|
2103
|
+
if (mapped && Object.keys(mapped).length > 0) {
|
|
2104
|
+
initialSubAgentPayload = mapped;
|
|
2105
|
+
if (params.verbose === true || (0, core_1.IsVerboseLoggingEnabled)()) {
|
|
2106
|
+
(0, core_1.LogStatus)(`Related sub-agent '${subAgentRequest.name}' receiving mapped payload: ${JSON.stringify(Object.keys(mapped))}`);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
let contextPaths = [];
|
|
2111
|
+
if (relationship.SubAgentContextPaths) {
|
|
2112
|
+
try {
|
|
2113
|
+
contextPaths = JSON.parse(relationship.SubAgentContextPaths);
|
|
2114
|
+
}
|
|
2115
|
+
catch (parseError) {
|
|
2116
|
+
(0, core_1.LogError)(`Failed to parse SubAgentContextPaths for sub-agent ${subAgentRequest.name}: ${parseError.message}`);
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
const contextMessage = this.prepareRelatedSubAgentContextMessage(previousDecision.newPayload, contextPaths);
|
|
2120
|
+
if (contextMessage && (params.verbose === true || (0, core_1.IsVerboseLoggingEnabled)())) {
|
|
2121
|
+
(0, core_1.LogStatus)(`Related sub-agent '${subAgentRequest.name}' receiving context from paths: ${contextPaths.join(', ')}`);
|
|
2122
|
+
}
|
|
2123
|
+
const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity, initialSubAgentPayload, contextMessage);
|
|
1847
2124
|
let mergedPayload = previousDecision.newPayload;
|
|
1848
2125
|
let currentStepPayloadChangeResult = undefined;
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
const payloadChange = this.applySubAgentOutputMapping(subAgentResult.payload, previousDecision.newPayload, relationshipWithMapping.SubAgentOutputMapping);
|
|
2126
|
+
if (subAgentResult.success && relationship.SubAgentOutputMapping) {
|
|
2127
|
+
const payloadChange = this.applySubAgentOutputMapping(subAgentResult.payload, previousDecision.newPayload, relationship.SubAgentOutputMapping);
|
|
1852
2128
|
if (payloadChange && payloadChange.updateElements) {
|
|
1853
2129
|
const mergeResult = this._payloadManager.applyAgentChangeRequest(previousDecision.newPayload, payloadChange, {
|
|
1854
2130
|
validateChanges: true,
|
|
@@ -1872,7 +2148,7 @@ class BaseAgent {
|
|
|
1872
2148
|
finalStep: subAgentResult.agentRun?.FinalStep,
|
|
1873
2149
|
errorMessage: subAgentResult.agentRun?.ErrorMessage,
|
|
1874
2150
|
stepCount: subAgentResult.agentRun?.Steps?.length || 0,
|
|
1875
|
-
hasMergedPayload: !!(
|
|
2151
|
+
hasMergedPayload: !!(relationship.SubAgentOutputMapping && mergedPayload !== previousDecision.newPayload)
|
|
1876
2152
|
},
|
|
1877
2153
|
shouldTerminate: shouldTerminate,
|
|
1878
2154
|
nextStep: shouldTerminate ? 'success' : 'retry',
|
|
@@ -1880,6 +2156,9 @@ class BaseAgent {
|
|
|
1880
2156
|
payloadChangeResult: currentStepPayloadChangeResult
|
|
1881
2157
|
})
|
|
1882
2158
|
};
|
|
2159
|
+
if (stepEntity) {
|
|
2160
|
+
stepEntity.PayloadAtEnd = JSON.stringify(mergedPayload);
|
|
2161
|
+
}
|
|
1883
2162
|
await this.finalizeStepEntity(stepEntity, subAgentResult.success, subAgentResult.agentRun?.ErrorMessage, outputData);
|
|
1884
2163
|
if (subAgentResult.agentRun?.FinalStep === 'Chat') {
|
|
1885
2164
|
return {
|
|
@@ -1901,9 +2180,6 @@ class BaseAgent {
|
|
|
1901
2180
|
role: 'user',
|
|
1902
2181
|
content: `Related sub-agent "${subAgentRequest.name}" completed:\n${JSON.stringify(subAgentSummary, null, 2)}`
|
|
1903
2182
|
});
|
|
1904
|
-
if (stepEntity) {
|
|
1905
|
-
stepEntity.PayloadAtEnd = JSON.stringify(mergedPayload);
|
|
1906
|
-
}
|
|
1907
2183
|
if (this._agentRun) {
|
|
1908
2184
|
this._agentRun.FinalPayloadObject = mergedPayload;
|
|
1909
2185
|
}
|
|
@@ -1965,6 +2241,72 @@ class BaseAgent {
|
|
|
1965
2241
|
return null;
|
|
1966
2242
|
}
|
|
1967
2243
|
}
|
|
2244
|
+
applySubAgentInputMapping(parentPayload, mappingConfig) {
|
|
2245
|
+
try {
|
|
2246
|
+
const mapping = JSON.parse(mappingConfig);
|
|
2247
|
+
const subAgentPayload = {};
|
|
2248
|
+
for (const [parentPath, subAgentPath] of Object.entries(mapping)) {
|
|
2249
|
+
let value;
|
|
2250
|
+
if (parentPath === '*') {
|
|
2251
|
+
value = parentPayload;
|
|
2252
|
+
}
|
|
2253
|
+
else {
|
|
2254
|
+
value = this.getValueFromPath(parentPayload, parentPath);
|
|
2255
|
+
}
|
|
2256
|
+
if (value !== undefined) {
|
|
2257
|
+
const pathParts = subAgentPath.split('.');
|
|
2258
|
+
let current = subAgentPayload;
|
|
2259
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
2260
|
+
const part = pathParts[i];
|
|
2261
|
+
if (!(part in current)) {
|
|
2262
|
+
current[part] = {};
|
|
2263
|
+
}
|
|
2264
|
+
current = current[part];
|
|
2265
|
+
}
|
|
2266
|
+
current[pathParts[pathParts.length - 1]] = value;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
if (Object.keys(subAgentPayload).length === 0) {
|
|
2270
|
+
return null;
|
|
2271
|
+
}
|
|
2272
|
+
return subAgentPayload;
|
|
2273
|
+
}
|
|
2274
|
+
catch (error) {
|
|
2275
|
+
(0, core_1.LogError)(`Failed to parse SubAgentInputMapping: ${error.message}`);
|
|
2276
|
+
return null;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
prepareRelatedSubAgentContextMessage(parentPayload, contextPaths) {
|
|
2280
|
+
if (!contextPaths || contextPaths.length === 0) {
|
|
2281
|
+
return null;
|
|
2282
|
+
}
|
|
2283
|
+
if (contextPaths.includes('*')) {
|
|
2284
|
+
return {
|
|
2285
|
+
role: 'user',
|
|
2286
|
+
content: `Parent Agent Context:\n\n${JSON.stringify(parentPayload, null, 2)}`
|
|
2287
|
+
};
|
|
2288
|
+
}
|
|
2289
|
+
const contextData = {};
|
|
2290
|
+
for (const path of contextPaths) {
|
|
2291
|
+
const value = this.getValueFromPath(parentPayload, path);
|
|
2292
|
+
if (value !== undefined) {
|
|
2293
|
+
contextData[path] = value;
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
if (Object.keys(contextData).length === 0) {
|
|
2297
|
+
return null;
|
|
2298
|
+
}
|
|
2299
|
+
const contextLines = Object.entries(contextData).map(([key, value]) => {
|
|
2300
|
+
const valueStr = typeof value === 'object'
|
|
2301
|
+
? JSON.stringify(value, null, 2)
|
|
2302
|
+
: String(value);
|
|
2303
|
+
return `${key}:\n${valueStr}`;
|
|
2304
|
+
});
|
|
2305
|
+
return {
|
|
2306
|
+
role: 'user',
|
|
2307
|
+
content: `Parent Agent Context:\n\n${contextLines.join('\n\n')}`
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
1968
2310
|
getValueFromPath(obj, path) {
|
|
1969
2311
|
const parts = path.split('.');
|
|
1970
2312
|
let current = obj;
|
|
@@ -2009,35 +2351,34 @@ class BaseAgent {
|
|
|
2009
2351
|
let progressMessage;
|
|
2010
2352
|
if (actions.length === 1) {
|
|
2011
2353
|
const aa = actions[0];
|
|
2012
|
-
progressMessage = `Executing
|
|
2354
|
+
progressMessage = `Executing **${aa.name}** action`;
|
|
2013
2355
|
if (aa.params && Object.keys(aa.params).length > 0) {
|
|
2014
2356
|
const paramsList = Object.entries(aa.params)
|
|
2015
2357
|
.map(([key, value]) => {
|
|
2016
|
-
const displayValue =
|
|
2017
|
-
|
|
2018
|
-
: String(value);
|
|
2019
|
-
return ` - \`${key}\`: ${displayValue}`;
|
|
2358
|
+
const displayValue = this.formatParamValueForMessage(value);
|
|
2359
|
+
return `• **${key}**: ${displayValue}`;
|
|
2020
2360
|
})
|
|
2021
2361
|
.join('\n');
|
|
2022
|
-
progressMessage +=
|
|
2362
|
+
progressMessage += ` with parameters:\n${paramsList}`;
|
|
2363
|
+
}
|
|
2364
|
+
else {
|
|
2365
|
+
progressMessage += '.';
|
|
2023
2366
|
}
|
|
2024
2367
|
}
|
|
2025
2368
|
else {
|
|
2026
|
-
progressMessage = `Executing
|
|
2027
|
-
|
|
2028
|
-
progressMessage += `\n\n• **${aa.name}**`;
|
|
2369
|
+
progressMessage = `Executing **${actions.length} actions** in parallel:\n\n` + actions.map((aa, index) => {
|
|
2370
|
+
let actionText = `${index + 1}. **${aa.name}**`;
|
|
2029
2371
|
if (aa.params && Object.keys(aa.params).length > 0) {
|
|
2030
2372
|
const paramsList = Object.entries(aa.params)
|
|
2031
2373
|
.map(([key, value]) => {
|
|
2032
|
-
const displayValue =
|
|
2033
|
-
|
|
2034
|
-
: String(value);
|
|
2035
|
-
return ` - \`${key}\`: ${displayValue}`;
|
|
2374
|
+
const displayValue = this.formatParamValueForMessage(value);
|
|
2375
|
+
return ` • **${key}**: ${displayValue}`;
|
|
2036
2376
|
})
|
|
2037
2377
|
.join('\n');
|
|
2038
|
-
|
|
2378
|
+
actionText += `\n${paramsList}`;
|
|
2039
2379
|
}
|
|
2040
|
-
|
|
2380
|
+
return actionText;
|
|
2381
|
+
}).join('\n\n');
|
|
2041
2382
|
}
|
|
2042
2383
|
params.onProgress?.({
|
|
2043
2384
|
step: 'action_execution',
|
|
@@ -2049,9 +2390,38 @@ class BaseAgent {
|
|
|
2049
2390
|
},
|
|
2050
2391
|
displayMode: 'live'
|
|
2051
2392
|
});
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2393
|
+
let actionMessage;
|
|
2394
|
+
if (actions.length === 1) {
|
|
2395
|
+
const aa = actions[0];
|
|
2396
|
+
actionMessage = `I'm executing the **${aa.name}** action`;
|
|
2397
|
+
if (aa.params && Object.keys(aa.params).length > 0) {
|
|
2398
|
+
const paramsList = Object.entries(aa.params)
|
|
2399
|
+
.map(([key, value]) => {
|
|
2400
|
+
const displayValue = this.formatParamValueForMessage(value);
|
|
2401
|
+
return `• **${key}**: ${displayValue}`;
|
|
2402
|
+
})
|
|
2403
|
+
.join('\n');
|
|
2404
|
+
actionMessage += ` with parameters:\n${paramsList}`;
|
|
2405
|
+
}
|
|
2406
|
+
else {
|
|
2407
|
+
actionMessage += '.';
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
else {
|
|
2411
|
+
actionMessage = `I'm executing **${actions.length} actions** in parallel:\n\n` + actions.map((aa, index) => {
|
|
2412
|
+
let actionText = `${index + 1}. **${aa.name}**`;
|
|
2413
|
+
if (aa.params && Object.keys(aa.params).length > 0) {
|
|
2414
|
+
const paramsList = Object.entries(aa.params)
|
|
2415
|
+
.map(([key, value]) => {
|
|
2416
|
+
const displayValue = this.formatParamValueForMessage(value);
|
|
2417
|
+
return ` • **${key}**: ${displayValue}`;
|
|
2418
|
+
})
|
|
2419
|
+
.join('\n');
|
|
2420
|
+
actionText += `\n${paramsList}`;
|
|
2421
|
+
}
|
|
2422
|
+
return actionText;
|
|
2423
|
+
}).join('\n\n');
|
|
2424
|
+
}
|
|
2055
2425
|
params.conversationMessages.push({
|
|
2056
2426
|
role: 'assistant',
|
|
2057
2427
|
content: actionMessage
|
|
@@ -2120,9 +2490,44 @@ class BaseAgent {
|
|
|
2120
2490
|
});
|
|
2121
2491
|
const failedActions = actionSummaries.filter(a => !a.success);
|
|
2122
2492
|
const resultsMessage = (failedActions.length > 0 ? `${failedActions.length} of ${actionSummaries.length} failed:` : `Action results:`) + `\n${JSON.stringify(actionSummaries, null, 2)}`;
|
|
2493
|
+
let metadata;
|
|
2494
|
+
const agentActionConfigs = actionResults
|
|
2495
|
+
.map(r => agentActions.find(aa => aa.ActionID === r.actionEntity.ID))
|
|
2496
|
+
.filter(aa => aa != null);
|
|
2497
|
+
if (agentActionConfigs.length > 0) {
|
|
2498
|
+
let minExpirationTurns = null;
|
|
2499
|
+
let expirationMode = 'None';
|
|
2500
|
+
let compactMode;
|
|
2501
|
+
let compactLength;
|
|
2502
|
+
let compactPromptId;
|
|
2503
|
+
for (const agentAction of agentActionConfigs) {
|
|
2504
|
+
if (agentAction.ResultExpirationTurns != null) {
|
|
2505
|
+
if (minExpirationTurns === null || agentAction.ResultExpirationTurns < minExpirationTurns) {
|
|
2506
|
+
minExpirationTurns = agentAction.ResultExpirationTurns;
|
|
2507
|
+
expirationMode = agentAction.ResultExpirationMode || 'None';
|
|
2508
|
+
compactMode = agentAction.CompactMode;
|
|
2509
|
+
compactLength = agentAction.CompactLength;
|
|
2510
|
+
compactPromptId = agentAction.CompactPromptID;
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
if (minExpirationTurns !== null && expirationMode !== 'None') {
|
|
2515
|
+
const currentStepCount = this._agentRun?.Steps?.length || 0;
|
|
2516
|
+
metadata = {
|
|
2517
|
+
turnAdded: currentStepCount,
|
|
2518
|
+
messageType: 'action-result',
|
|
2519
|
+
expirationTurns: minExpirationTurns,
|
|
2520
|
+
expirationMode: expirationMode,
|
|
2521
|
+
compactMode: compactMode,
|
|
2522
|
+
compactLength: compactLength,
|
|
2523
|
+
compactPromptId: compactPromptId
|
|
2524
|
+
};
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2123
2527
|
params.conversationMessages.push({
|
|
2124
2528
|
role: 'user',
|
|
2125
|
-
content: resultsMessage
|
|
2529
|
+
content: resultsMessage,
|
|
2530
|
+
metadata: metadata
|
|
2126
2531
|
});
|
|
2127
2532
|
let finalPayload = currentPayload;
|
|
2128
2533
|
try {
|
|
@@ -2188,6 +2593,7 @@ class BaseAgent {
|
|
|
2188
2593
|
confidence: previousDecision.confidence,
|
|
2189
2594
|
previousPayload: previousDecision.previousPayload,
|
|
2190
2595
|
newPayload: previousDecision.newPayload || previousDecision.previousPayload,
|
|
2596
|
+
suggestedResponses: previousDecision.suggestedResponses
|
|
2191
2597
|
};
|
|
2192
2598
|
}
|
|
2193
2599
|
async createFailureResult(errorMessage, contextUser) {
|
|
@@ -2257,7 +2663,8 @@ class BaseAgent {
|
|
|
2257
2663
|
return {
|
|
2258
2664
|
success: finalStep.step === 'Success' || finalStep.step === 'Chat',
|
|
2259
2665
|
payload,
|
|
2260
|
-
agentRun: this._agentRun
|
|
2666
|
+
agentRun: this._agentRun,
|
|
2667
|
+
suggestedResponses: finalStep.suggestedResponses
|
|
2261
2668
|
};
|
|
2262
2669
|
}
|
|
2263
2670
|
calculateTokenStats() {
|
|
@@ -2318,6 +2725,236 @@ class BaseAgent {
|
|
|
2318
2725
|
}
|
|
2319
2726
|
return violations;
|
|
2320
2727
|
}
|
|
2728
|
+
async pruneAndCompactExpiredMessages(params, currentTurn) {
|
|
2729
|
+
const messagesToCompact = [];
|
|
2730
|
+
const messagesToRemove = [];
|
|
2731
|
+
for (let i = 0; i < params.conversationMessages.length; i++) {
|
|
2732
|
+
const msg = params.conversationMessages[i];
|
|
2733
|
+
if (!msg.metadata?.expirationTurns && msg.metadata?.expirationTurns !== 0) {
|
|
2734
|
+
continue;
|
|
2735
|
+
}
|
|
2736
|
+
if (msg.metadata.expirationMode === 'None') {
|
|
2737
|
+
continue;
|
|
2738
|
+
}
|
|
2739
|
+
const turnAdded = msg.metadata.turnAdded || 0;
|
|
2740
|
+
const turnsAlive = currentTurn - turnAdded;
|
|
2741
|
+
if (turnsAlive > msg.metadata.expirationTurns) {
|
|
2742
|
+
msg.metadata.isExpired = true;
|
|
2743
|
+
if (msg.metadata.expirationMode === 'Remove') {
|
|
2744
|
+
messagesToRemove.push(i);
|
|
2745
|
+
this.emitMessageLifecycleEvent({
|
|
2746
|
+
type: 'message-expired',
|
|
2747
|
+
turn: currentTurn,
|
|
2748
|
+
messageIndex: i,
|
|
2749
|
+
message: msg,
|
|
2750
|
+
reason: `Expired after ${turnsAlive} turns (limit: ${msg.metadata.expirationTurns})`
|
|
2751
|
+
});
|
|
2752
|
+
}
|
|
2753
|
+
else if (msg.metadata.expirationMode === 'Compact') {
|
|
2754
|
+
if (msg.metadata.compactMode) {
|
|
2755
|
+
messagesToCompact.push({
|
|
2756
|
+
index: i,
|
|
2757
|
+
message: msg,
|
|
2758
|
+
metadata: {
|
|
2759
|
+
compactMode: msg.metadata.compactMode,
|
|
2760
|
+
compactLength: msg.metadata.compactLength || 500,
|
|
2761
|
+
compactPromptId: msg.metadata.compactPromptId || '',
|
|
2762
|
+
originalLength: typeof msg.content === 'string'
|
|
2763
|
+
? msg.content.length
|
|
2764
|
+
: JSON.stringify(msg.content).length
|
|
2765
|
+
}
|
|
2766
|
+
});
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
const preserveOriginal = params.messageExpirationOverride?.preserveOriginalContent !== false;
|
|
2772
|
+
for (const item of messagesToCompact) {
|
|
2773
|
+
const originalContent = item.message.content;
|
|
2774
|
+
const compacted = await this.compactMessage(item.message, item.metadata, params);
|
|
2775
|
+
const originalTokens = this.estimateTokens(originalContent);
|
|
2776
|
+
const compactedTokens = this.estimateTokens(compacted);
|
|
2777
|
+
const tokensSaved = originalTokens - compactedTokens;
|
|
2778
|
+
params.conversationMessages[item.index] = {
|
|
2779
|
+
...item.message,
|
|
2780
|
+
content: compacted,
|
|
2781
|
+
metadata: {
|
|
2782
|
+
...item.message.metadata,
|
|
2783
|
+
wasCompacted: true,
|
|
2784
|
+
originalContent: preserveOriginal ? originalContent : undefined,
|
|
2785
|
+
originalLength: item.metadata.originalLength,
|
|
2786
|
+
tokensSaved,
|
|
2787
|
+
canExpand: preserveOriginal
|
|
2788
|
+
}
|
|
2789
|
+
};
|
|
2790
|
+
this.emitMessageLifecycleEvent({
|
|
2791
|
+
type: 'message-compacted',
|
|
2792
|
+
turn: currentTurn,
|
|
2793
|
+
messageIndex: item.index,
|
|
2794
|
+
message: params.conversationMessages[item.index],
|
|
2795
|
+
reason: `Compacted using ${item.metadata.compactMode} (saved ${tokensSaved} tokens)`,
|
|
2796
|
+
tokensSaved
|
|
2797
|
+
});
|
|
2798
|
+
}
|
|
2799
|
+
for (let i = messagesToRemove.length - 1; i >= 0; i--) {
|
|
2800
|
+
const index = messagesToRemove[i];
|
|
2801
|
+
const removed = params.conversationMessages.splice(index, 1)[0];
|
|
2802
|
+
this.emitMessageLifecycleEvent({
|
|
2803
|
+
type: 'message-removed',
|
|
2804
|
+
turn: currentTurn,
|
|
2805
|
+
messageIndex: index,
|
|
2806
|
+
message: removed,
|
|
2807
|
+
reason: 'Removed due to expiration'
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2810
|
+
if (params.verbose && (messagesToCompact.length > 0 || messagesToRemove.length > 0)) {
|
|
2811
|
+
const totalSaved = messagesToCompact.reduce((sum, item) => {
|
|
2812
|
+
const msg = params.conversationMessages[item.index];
|
|
2813
|
+
return sum + (msg.metadata?.tokensSaved || 0);
|
|
2814
|
+
}, 0);
|
|
2815
|
+
console.log(`[Turn ${currentTurn}] Message pruning: ` +
|
|
2816
|
+
`${messagesToCompact.length} compacted (saved ~${totalSaved} tokens), ` +
|
|
2817
|
+
`${messagesToRemove.length} removed`);
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
async createCompactionStep(prompt, message, params) {
|
|
2821
|
+
if (!this._agentRun) {
|
|
2822
|
+
throw new Error('Cannot create compaction step: agent run not initialized');
|
|
2823
|
+
}
|
|
2824
|
+
const md = new core_1.Metadata();
|
|
2825
|
+
const step = await md.GetEntityObject('MJ: AI Agent Run Steps', params.contextUser);
|
|
2826
|
+
step.NewRecord();
|
|
2827
|
+
step.AgentRunID = this._agentRun.ID;
|
|
2828
|
+
step.StepType = 'Prompt';
|
|
2829
|
+
step.Status = 'Running';
|
|
2830
|
+
step.InputData = JSON.stringify({
|
|
2831
|
+
stepName: 'Message Compaction',
|
|
2832
|
+
description: `Compacting message using AI Summary (${message.metadata?.messageType || 'unknown'} from turn ${message.metadata?.turnAdded || 0})`,
|
|
2833
|
+
messageType: message.metadata?.messageType,
|
|
2834
|
+
turnAdded: message.metadata?.turnAdded,
|
|
2835
|
+
originalLength: message.metadata?.originalLength ||
|
|
2836
|
+
(typeof message.content === 'string' ? message.content.length : JSON.stringify(message.content).length),
|
|
2837
|
+
compactMode: 'AI Summary',
|
|
2838
|
+
promptId: prompt.ID,
|
|
2839
|
+
promptName: prompt.Name
|
|
2840
|
+
});
|
|
2841
|
+
await step.Save();
|
|
2842
|
+
return step;
|
|
2843
|
+
}
|
|
2844
|
+
async updateCompactionStep(step, result, message, params) {
|
|
2845
|
+
step.Status = result.success ? 'Completed' : 'Failed';
|
|
2846
|
+
const promptTokens = result.promptTokens || 0;
|
|
2847
|
+
const completionTokens = result.completionTokens || 0;
|
|
2848
|
+
step.OutputData = JSON.stringify({
|
|
2849
|
+
success: result.success,
|
|
2850
|
+
summaryLength: result.result?.summary?.length || 0,
|
|
2851
|
+
tokensSaved: message.metadata?.tokensSaved || 0,
|
|
2852
|
+
promptTokens,
|
|
2853
|
+
completionTokens,
|
|
2854
|
+
totalTokens: promptTokens + completionTokens,
|
|
2855
|
+
cost: result.cost
|
|
2856
|
+
});
|
|
2857
|
+
if (!result.success) {
|
|
2858
|
+
step.ErrorMessage = result.errorMessage || 'AI Summary compaction failed';
|
|
2859
|
+
}
|
|
2860
|
+
await step.Save();
|
|
2861
|
+
}
|
|
2862
|
+
async compactMessage(message, metadata, params) {
|
|
2863
|
+
const originalContent = typeof message.content === 'string'
|
|
2864
|
+
? message.content
|
|
2865
|
+
: JSON.stringify(message.content);
|
|
2866
|
+
switch (metadata.compactMode) {
|
|
2867
|
+
case 'First N Chars': {
|
|
2868
|
+
const length = metadata.compactLength;
|
|
2869
|
+
if (originalContent.length <= length) {
|
|
2870
|
+
return originalContent;
|
|
2871
|
+
}
|
|
2872
|
+
const truncated = originalContent.substring(0, length);
|
|
2873
|
+
return `${truncated}...\n\n[Compacted: showing first ${length} of ${originalContent.length} characters. Agent can request expansion if needed.]`;
|
|
2874
|
+
}
|
|
2875
|
+
case 'AI Summary': {
|
|
2876
|
+
try {
|
|
2877
|
+
const promptId = metadata.compactPromptId || this.getSystemDefaultCompactPromptId();
|
|
2878
|
+
const prompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.ID === promptId);
|
|
2879
|
+
if (!prompt) {
|
|
2880
|
+
console.warn(`Compact prompt ${promptId} not found, falling back to First N Chars`);
|
|
2881
|
+
return this.compactMessage(message, { ...metadata, compactMode: 'First N Chars' }, params);
|
|
2882
|
+
}
|
|
2883
|
+
const step = await this.createCompactionStep(prompt, message, params);
|
|
2884
|
+
const promptParams = new ai_core_plus_1.AIPromptParams();
|
|
2885
|
+
promptParams.prompt = prompt;
|
|
2886
|
+
promptParams.data = {
|
|
2887
|
+
originalContent,
|
|
2888
|
+
originalLength: metadata.originalLength,
|
|
2889
|
+
targetLength: metadata.compactLength || 500,
|
|
2890
|
+
messageType: message.metadata?.messageType || 'unknown',
|
|
2891
|
+
turnAdded: message.metadata?.turnAdded || 0
|
|
2892
|
+
};
|
|
2893
|
+
promptParams.contextUser = params.contextUser;
|
|
2894
|
+
const runner = new ai_prompts_1.AIPromptRunner();
|
|
2895
|
+
const result = await runner.ExecutePrompt(promptParams);
|
|
2896
|
+
await this.updateCompactionStep(step, result, message, params);
|
|
2897
|
+
if (!result.success || !result.result?.summary) {
|
|
2898
|
+
console.warn('AI summary failed, falling back to First N Chars');
|
|
2899
|
+
return this.compactMessage(message, { ...metadata, compactMode: 'First N Chars' }, params);
|
|
2900
|
+
}
|
|
2901
|
+
return `[AI Summary of ${metadata.originalLength} chars. Agent can request full expansion if needed.]\n\n${result.result.summary}`;
|
|
2902
|
+
}
|
|
2903
|
+
catch (error) {
|
|
2904
|
+
console.error('Error during AI summary:', error);
|
|
2905
|
+
return this.compactMessage(message, { ...metadata, compactMode: 'First N Chars' }, params);
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
default:
|
|
2909
|
+
return originalContent;
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
getSystemDefaultCompactPromptId() {
|
|
2913
|
+
const prompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Compact Agent Message');
|
|
2914
|
+
if (!prompt) {
|
|
2915
|
+
console.warn('System default compact prompt not found. Ensure "Compact Agent Message" prompt exists.');
|
|
2916
|
+
return '';
|
|
2917
|
+
}
|
|
2918
|
+
return prompt.ID;
|
|
2919
|
+
}
|
|
2920
|
+
estimateTokens(content) {
|
|
2921
|
+
const text = typeof content === 'string'
|
|
2922
|
+
? content
|
|
2923
|
+
: JSON.stringify(content);
|
|
2924
|
+
return Math.ceil(text.length / 4);
|
|
2925
|
+
}
|
|
2926
|
+
emitMessageLifecycleEvent(event) {
|
|
2927
|
+
if (this._messageLifecycleCallback) {
|
|
2928
|
+
this._messageLifecycleCallback(event);
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
executeExpandMessageStep(request, params, currentTurn) {
|
|
2932
|
+
const messageIndex = request.messageIndex;
|
|
2933
|
+
const reason = request.expandReason;
|
|
2934
|
+
if (messageIndex === undefined || messageIndex < 0 || messageIndex >= params.conversationMessages.length) {
|
|
2935
|
+
console.warn(`Cannot expand message: index ${messageIndex} out of bounds`);
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
const message = params.conversationMessages[messageIndex];
|
|
2939
|
+
if (!message.metadata?.canExpand || !message.metadata?.originalContent) {
|
|
2940
|
+
console.warn(`Cannot expand message at index ${messageIndex}: not expandable or no original content`);
|
|
2941
|
+
return;
|
|
2942
|
+
}
|
|
2943
|
+
message.content = message.metadata.originalContent;
|
|
2944
|
+
message.metadata.wasCompacted = false;
|
|
2945
|
+
message.metadata.canExpand = false;
|
|
2946
|
+
delete message.metadata.originalContent;
|
|
2947
|
+
this.emitMessageLifecycleEvent({
|
|
2948
|
+
type: 'message-expanded',
|
|
2949
|
+
turn: currentTurn,
|
|
2950
|
+
messageIndex,
|
|
2951
|
+
message,
|
|
2952
|
+
reason: reason || 'Agent requested expansion'
|
|
2953
|
+
});
|
|
2954
|
+
if (params.verbose) {
|
|
2955
|
+
console.log(`[Turn ${currentTurn}] Expanded message at index ${messageIndex}`);
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2321
2958
|
}
|
|
2322
2959
|
exports.BaseAgent = BaseAgent;
|
|
2323
2960
|
BaseAgent.MAX_VALIDATION_RETRIES = 10;
|