@memberjunction/ai-agents 2.107.0 → 2.108.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 +154 -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 +32 -4
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +624 -36
- package/dist/base-agent.js.map +1 -1
- package/package.json +8 -8
package/dist/base-agent.js
CHANGED
|
@@ -49,6 +49,7 @@ class BaseAgent {
|
|
|
49
49
|
this._subAgentRuns = [];
|
|
50
50
|
this._payloadManager = new PayloadManager_1.PayloadManager();
|
|
51
51
|
this._validationRetryCount = 0;
|
|
52
|
+
this._contextRecoveryAttempted = false;
|
|
52
53
|
}
|
|
53
54
|
get AgentTypeState() {
|
|
54
55
|
return this._agentTypeState;
|
|
@@ -158,6 +159,8 @@ class BaseAgent {
|
|
|
158
159
|
await this.initializeAgentRun(wrappedParams);
|
|
159
160
|
this._validationRetryCount = 0;
|
|
160
161
|
this._generalValidationRetryCount = 0;
|
|
162
|
+
this._contextRecoveryAttempted = false;
|
|
163
|
+
this._messageLifecycleCallback = params.onMessageLifecycle;
|
|
161
164
|
await this.initializeEngines(params.contextUser);
|
|
162
165
|
if (params.cancellationToken?.aborted) {
|
|
163
166
|
return await this.createCancelledResult('Cancelled during initialization', params.contextUser);
|
|
@@ -219,6 +222,7 @@ class BaseAgent {
|
|
|
219
222
|
if (params.cancellationToken?.aborted) {
|
|
220
223
|
throw new Error('Cancelled during execution');
|
|
221
224
|
}
|
|
225
|
+
await this.pruneAndCompactExpiredMessages(params, stepCount);
|
|
222
226
|
this.logStatus(`🔄 Executing step ${stepCount + 1} for agent '${params.agent.Name}'`, true, params);
|
|
223
227
|
const nextStep = await this.executeNextStep(params, config, currentNextStep);
|
|
224
228
|
stepCount++;
|
|
@@ -897,6 +901,163 @@ class BaseAgent {
|
|
|
897
901
|
}
|
|
898
902
|
return { exceeded: false };
|
|
899
903
|
}
|
|
904
|
+
isFatalPromptError(promptResult) {
|
|
905
|
+
if (!promptResult?.chatResult?.errorInfo) {
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
const errorInfo = promptResult.chatResult.errorInfo;
|
|
909
|
+
if (errorInfo.severity === 'Fatal') {
|
|
910
|
+
return true;
|
|
911
|
+
}
|
|
912
|
+
const fatalErrorTypes = [
|
|
913
|
+
'ContextLengthExceeded',
|
|
914
|
+
'Authentication',
|
|
915
|
+
'InvalidRequest'
|
|
916
|
+
];
|
|
917
|
+
return fatalErrorTypes.includes(errorInfo.errorType);
|
|
918
|
+
}
|
|
919
|
+
contentToString(content) {
|
|
920
|
+
if (typeof content === 'string') {
|
|
921
|
+
return content;
|
|
922
|
+
}
|
|
923
|
+
return content.map((block) => {
|
|
924
|
+
if (block.type === 'text') {
|
|
925
|
+
return block.content;
|
|
926
|
+
}
|
|
927
|
+
return `[${block.type}: ${block.content}]`;
|
|
928
|
+
}).join('\n');
|
|
929
|
+
}
|
|
930
|
+
smartTrimContent(content, maxLength = 1000) {
|
|
931
|
+
const originalLength = content.length;
|
|
932
|
+
try {
|
|
933
|
+
const data = JSON.parse(content);
|
|
934
|
+
if (Array.isArray(data)) {
|
|
935
|
+
const itemsToKeep = 10;
|
|
936
|
+
if (data.length > itemsToKeep) {
|
|
937
|
+
const truncated = data.slice(0, itemsToKeep);
|
|
938
|
+
const trimmed = JSON.stringify(truncated, null, 2) +
|
|
939
|
+
`\n\n... (${(data.length - itemsToKeep).toLocaleString()} more items truncated due to context length)`;
|
|
940
|
+
return {
|
|
941
|
+
trimmed,
|
|
942
|
+
strategy: 'JSON array truncation',
|
|
943
|
+
originalLength
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
else if (typeof data === 'object' && data !== null) {
|
|
948
|
+
const truncated = {};
|
|
949
|
+
let fieldCount = 0;
|
|
950
|
+
const maxFields = 20;
|
|
951
|
+
for (const [key, value] of Object.entries(data)) {
|
|
952
|
+
if (fieldCount >= maxFields) {
|
|
953
|
+
truncated['...'] = `(${Object.keys(data).length - maxFields} more fields truncated)`;
|
|
954
|
+
break;
|
|
955
|
+
}
|
|
956
|
+
if (typeof value === 'string' && value.length > 200) {
|
|
957
|
+
truncated[key] = value.substring(0, 200) + '... (truncated)';
|
|
958
|
+
}
|
|
959
|
+
else if (Array.isArray(value) && value.length > 5) {
|
|
960
|
+
truncated[key] = [...value.slice(0, 5), `... (${value.length - 5} more items)`];
|
|
961
|
+
}
|
|
962
|
+
else {
|
|
963
|
+
truncated[key] = value;
|
|
964
|
+
}
|
|
965
|
+
fieldCount++;
|
|
966
|
+
}
|
|
967
|
+
return {
|
|
968
|
+
trimmed: JSON.stringify(truncated, null, 2),
|
|
969
|
+
strategy: 'JSON object field truncation',
|
|
970
|
+
originalLength
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
catch {
|
|
975
|
+
}
|
|
976
|
+
if (content.includes('\n')) {
|
|
977
|
+
const lines = content.split('\n');
|
|
978
|
+
const firstLine = lines[0];
|
|
979
|
+
if (firstLine.includes(',') && lines.length > 1) {
|
|
980
|
+
const rowsToKeep = 10;
|
|
981
|
+
if (lines.length > rowsToKeep + 1) {
|
|
982
|
+
const header = lines[0];
|
|
983
|
+
const dataRows = lines.slice(1, rowsToKeep + 1);
|
|
984
|
+
const trimmed = [header, ...dataRows].join('\n') +
|
|
985
|
+
`\n... (${(lines.length - rowsToKeep - 1).toLocaleString()} more rows truncated due to context length)`;
|
|
986
|
+
return {
|
|
987
|
+
trimmed,
|
|
988
|
+
strategy: 'CSV row truncation',
|
|
989
|
+
originalLength
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
if (content.length > maxLength) {
|
|
995
|
+
return {
|
|
996
|
+
trimmed: content.substring(0, maxLength) + '\n\n... (truncated due to context length)',
|
|
997
|
+
strategy: 'character truncation',
|
|
998
|
+
originalLength
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
return {
|
|
1002
|
+
trimmed: content,
|
|
1003
|
+
strategy: 'no truncation needed',
|
|
1004
|
+
originalLength
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
async attemptContextRecovery(params, payload, errorMessage) {
|
|
1008
|
+
this.logStatus(`⚠️ Context length exceeded - attempting recovery by trimming conversation messages`, true, params);
|
|
1009
|
+
const messages = params.conversationMessages;
|
|
1010
|
+
let lastUserMessageIndex = -1;
|
|
1011
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1012
|
+
if (messages[i].role === 'user') {
|
|
1013
|
+
lastUserMessageIndex = i;
|
|
1014
|
+
break;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
if (lastUserMessageIndex === -1) {
|
|
1018
|
+
this.logStatus(`❌ Context recovery failed: No trimmable user messages found`, true, params);
|
|
1019
|
+
return {
|
|
1020
|
+
errorMessage: `Context overflow with no trimmable messages: ${errorMessage}`,
|
|
1021
|
+
step: 'Failed',
|
|
1022
|
+
terminate: true,
|
|
1023
|
+
previousPayload: payload,
|
|
1024
|
+
newPayload: payload
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
const originalMessage = messages[lastUserMessageIndex];
|
|
1028
|
+
const contentString = this.contentToString(originalMessage.content);
|
|
1029
|
+
const trimResult = this.smartTrimContent(contentString, 1000);
|
|
1030
|
+
this.logStatus(`✂️ Trimmed message from ${trimResult.originalLength.toLocaleString()} to ${trimResult.trimmed.length.toLocaleString()} characters using ${trimResult.strategy}`, true, params);
|
|
1031
|
+
messages[lastUserMessageIndex] = {
|
|
1032
|
+
role: 'user',
|
|
1033
|
+
content: `⚠️ CONTEXT OVERFLOW RECOVERY ⚠️
|
|
1034
|
+
|
|
1035
|
+
The previous step returned a result that exceeded the context window (${(trimResult.originalLength - trimResult.trimmed.length).toLocaleString()} characters truncated).
|
|
1036
|
+
|
|
1037
|
+
Here is a PARTIAL result from the previous action:
|
|
1038
|
+
---
|
|
1039
|
+
${trimResult.trimmed}
|
|
1040
|
+
---
|
|
1041
|
+
|
|
1042
|
+
❗ THE ABOVE IS INCOMPLETE - the full result was too large for the context window.
|
|
1043
|
+
|
|
1044
|
+
RECOMMENDED ACTIONS:
|
|
1045
|
+
1. Use a different action with more specific filters to get smaller result sets
|
|
1046
|
+
2. Request data in batches or pages instead of all at once
|
|
1047
|
+
3. Ask the user to clarify scope to narrow the query
|
|
1048
|
+
4. If you need the full data, acknowledge the limitation and ask the user how to proceed
|
|
1049
|
+
|
|
1050
|
+
Please choose an alternative approach to complete your task.`
|
|
1051
|
+
};
|
|
1052
|
+
return {
|
|
1053
|
+
step: 'Retry',
|
|
1054
|
+
retryReason: 'Context length recovery - previous result too large',
|
|
1055
|
+
retryInstructions: 'The previous action result exceeded context limits. Use more specific filters or request data in smaller batches.',
|
|
1056
|
+
terminate: false,
|
|
1057
|
+
previousPayload: payload,
|
|
1058
|
+
newPayload: payload
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
900
1061
|
async processNextStep(nextStep, params, agentType, promptResult, currentPayload, currentStep) {
|
|
901
1062
|
const validatedNextStep = await this.validateNextStep(params, nextStep, currentPayload, this._agentRun, currentStep);
|
|
902
1063
|
const guardrailCheckedStep = await this.checkExecutionGuardrails(params, validatedNextStep, currentPayload, this._agentRun, currentStep);
|
|
@@ -1006,16 +1167,18 @@ class BaseAgent {
|
|
|
1006
1167
|
throw new Error(`Error executing actions: ${error.message}`);
|
|
1007
1168
|
}
|
|
1008
1169
|
}
|
|
1009
|
-
async ExecuteSubAgent(params, subAgentRequest, subAgent, stepEntity, payload) {
|
|
1170
|
+
async ExecuteSubAgent(params, subAgentRequest, subAgent, stepEntity, payload, contextMessage) {
|
|
1010
1171
|
try {
|
|
1011
1172
|
this.logStatus(`🤖 Executing sub-agent '${subAgentRequest.name}'`, true, params);
|
|
1012
1173
|
const runner = new AgentRunner_1.AgentRunner();
|
|
1013
|
-
const subAgentMessages = [
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1174
|
+
const subAgentMessages = [];
|
|
1175
|
+
if (contextMessage) {
|
|
1176
|
+
subAgentMessages.push(contextMessage);
|
|
1177
|
+
}
|
|
1178
|
+
subAgentMessages.push({
|
|
1179
|
+
role: 'user',
|
|
1180
|
+
content: subAgentRequest.message
|
|
1181
|
+
});
|
|
1019
1182
|
this.logStatus(`📨 Sub-agent message: "${subAgentRequest.message}"`, true, params);
|
|
1020
1183
|
if (subAgentRequest.templateParameters) {
|
|
1021
1184
|
this.logStatus(`📎 Template parameters: ${JSON.stringify(subAgentRequest.templateParameters)}`, true, params);
|
|
@@ -1134,6 +1297,25 @@ class BaseAgent {
|
|
|
1134
1297
|
ValueType: param.ValueType
|
|
1135
1298
|
};
|
|
1136
1299
|
}
|
|
1300
|
+
formatParamValueForMessage(value, maxLength = 100) {
|
|
1301
|
+
if (value === null || value === undefined) {
|
|
1302
|
+
return 'null';
|
|
1303
|
+
}
|
|
1304
|
+
let stringValue;
|
|
1305
|
+
if (typeof value === 'string') {
|
|
1306
|
+
stringValue = value;
|
|
1307
|
+
}
|
|
1308
|
+
else if (typeof value === 'object') {
|
|
1309
|
+
stringValue = JSON.stringify(value);
|
|
1310
|
+
}
|
|
1311
|
+
else {
|
|
1312
|
+
stringValue = String(value);
|
|
1313
|
+
}
|
|
1314
|
+
if (stringValue.length > maxLength) {
|
|
1315
|
+
return `\`${stringValue.substring(0, maxLength)}...\``;
|
|
1316
|
+
}
|
|
1317
|
+
return `\`${stringValue}\``;
|
|
1318
|
+
}
|
|
1137
1319
|
getAgentTypeName(typeID) {
|
|
1138
1320
|
const agentType = aiengine_1.AIEngine.Instance.AgentTypes.find(at => at.ID === typeID);
|
|
1139
1321
|
return agentType?.Name || 'Unknown';
|
|
@@ -1364,6 +1546,10 @@ class BaseAgent {
|
|
|
1364
1546
|
}
|
|
1365
1547
|
switch (previousDecision.step) {
|
|
1366
1548
|
case 'Retry':
|
|
1549
|
+
if (previousDecision.messageIndex !== undefined) {
|
|
1550
|
+
const currentStepCount = this._agentRun?.Steps?.length || 0;
|
|
1551
|
+
this.executeExpandMessageStep(previousDecision, params, currentStepCount);
|
|
1552
|
+
}
|
|
1367
1553
|
return await this.executePromptStep(params, config, previousDecision);
|
|
1368
1554
|
case 'Sub-Agent':
|
|
1369
1555
|
return await this.processSubAgentStep(params, previousDecision);
|
|
@@ -1466,6 +1652,25 @@ class BaseAgent {
|
|
|
1466
1652
|
stepEntity.TargetLogID = promptResult.promptRun.ID;
|
|
1467
1653
|
stepEntity.PromptRun = promptResult.promptRun;
|
|
1468
1654
|
}
|
|
1655
|
+
if (!promptResult.success) {
|
|
1656
|
+
await this.finalizeStepEntity(stepEntity, false, promptResult.errorMessage);
|
|
1657
|
+
const isFatal = this.isFatalPromptError(promptResult);
|
|
1658
|
+
const isContextOverflow = isFatal &&
|
|
1659
|
+
promptResult.chatResult?.errorInfo?.errorType === 'ContextLengthExceeded';
|
|
1660
|
+
if (isContextOverflow && !this._contextRecoveryAttempted) {
|
|
1661
|
+
this._contextRecoveryAttempted = true;
|
|
1662
|
+
this.logStatus(`⚠️ Context length exceeded - attempting recovery by trimming conversation`, true, params);
|
|
1663
|
+
return await this.attemptContextRecovery(params, payload, promptResult.errorMessage || 'Context length exceeded');
|
|
1664
|
+
}
|
|
1665
|
+
this.logStatus(`❌ Prompt execution failed: ${promptResult.errorMessage} (fatal: ${isFatal})`, true, params);
|
|
1666
|
+
return {
|
|
1667
|
+
errorMessage: promptResult.errorMessage || 'Prompt execution failed',
|
|
1668
|
+
step: 'Failed',
|
|
1669
|
+
terminate: isFatal,
|
|
1670
|
+
previousPayload: payload,
|
|
1671
|
+
newPayload: payload
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1469
1674
|
if (params.cancellationToken?.aborted) {
|
|
1470
1675
|
await this.finalizeStepEntity(stepEntity, false, 'Cancelled during prompt execution');
|
|
1471
1676
|
const cancelledResult = await this.createCancelledResult('Cancelled during prompt execution', params.contextUser);
|
|
@@ -1631,7 +1836,7 @@ class BaseAgent {
|
|
|
1631
1836
|
}
|
|
1632
1837
|
}
|
|
1633
1838
|
stepEntity.PayloadAtStart = JSON.stringify(previousDecision.newPayload);
|
|
1634
|
-
const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity, scopedPayload);
|
|
1839
|
+
const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity, scopedPayload, undefined);
|
|
1635
1840
|
let mergedPayload = previousDecision.newPayload;
|
|
1636
1841
|
let currentStepPayloadChangeResult = undefined;
|
|
1637
1842
|
if (subAgentResult.success) {
|
|
@@ -1843,12 +2048,34 @@ class BaseAgent {
|
|
|
1843
2048
|
this.incrementExecutionCount(subAgentEntity.ID);
|
|
1844
2049
|
try {
|
|
1845
2050
|
stepEntity.PayloadAtStart = JSON.stringify(previousDecision.newPayload);
|
|
1846
|
-
|
|
2051
|
+
let initialSubAgentPayload = undefined;
|
|
2052
|
+
if (relationship.SubAgentInputMapping) {
|
|
2053
|
+
const mapped = this.applySubAgentInputMapping(previousDecision.newPayload, relationship.SubAgentInputMapping);
|
|
2054
|
+
if (mapped && Object.keys(mapped).length > 0) {
|
|
2055
|
+
initialSubAgentPayload = mapped;
|
|
2056
|
+
if (params.verbose === true || (0, core_1.IsVerboseLoggingEnabled)()) {
|
|
2057
|
+
(0, core_1.LogStatus)(`Related sub-agent '${subAgentRequest.name}' receiving mapped payload: ${JSON.stringify(Object.keys(mapped))}`);
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
let contextPaths = [];
|
|
2062
|
+
if (relationship.SubAgentContextPaths) {
|
|
2063
|
+
try {
|
|
2064
|
+
contextPaths = JSON.parse(relationship.SubAgentContextPaths);
|
|
2065
|
+
}
|
|
2066
|
+
catch (parseError) {
|
|
2067
|
+
(0, core_1.LogError)(`Failed to parse SubAgentContextPaths for sub-agent ${subAgentRequest.name}: ${parseError.message}`);
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
const contextMessage = this.prepareRelatedSubAgentContextMessage(previousDecision.newPayload, contextPaths);
|
|
2071
|
+
if (contextMessage && (params.verbose === true || (0, core_1.IsVerboseLoggingEnabled)())) {
|
|
2072
|
+
(0, core_1.LogStatus)(`Related sub-agent '${subAgentRequest.name}' receiving context from paths: ${contextPaths.join(', ')}`);
|
|
2073
|
+
}
|
|
2074
|
+
const subAgentResult = await this.ExecuteSubAgent(params, subAgentRequest, subAgentEntity, stepEntity, initialSubAgentPayload, contextMessage);
|
|
1847
2075
|
let mergedPayload = previousDecision.newPayload;
|
|
1848
2076
|
let currentStepPayloadChangeResult = undefined;
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
const payloadChange = this.applySubAgentOutputMapping(subAgentResult.payload, previousDecision.newPayload, relationshipWithMapping.SubAgentOutputMapping);
|
|
2077
|
+
if (subAgentResult.success && relationship.SubAgentOutputMapping) {
|
|
2078
|
+
const payloadChange = this.applySubAgentOutputMapping(subAgentResult.payload, previousDecision.newPayload, relationship.SubAgentOutputMapping);
|
|
1852
2079
|
if (payloadChange && payloadChange.updateElements) {
|
|
1853
2080
|
const mergeResult = this._payloadManager.applyAgentChangeRequest(previousDecision.newPayload, payloadChange, {
|
|
1854
2081
|
validateChanges: true,
|
|
@@ -1872,7 +2099,7 @@ class BaseAgent {
|
|
|
1872
2099
|
finalStep: subAgentResult.agentRun?.FinalStep,
|
|
1873
2100
|
errorMessage: subAgentResult.agentRun?.ErrorMessage,
|
|
1874
2101
|
stepCount: subAgentResult.agentRun?.Steps?.length || 0,
|
|
1875
|
-
hasMergedPayload: !!(
|
|
2102
|
+
hasMergedPayload: !!(relationship.SubAgentOutputMapping && mergedPayload !== previousDecision.newPayload)
|
|
1876
2103
|
},
|
|
1877
2104
|
shouldTerminate: shouldTerminate,
|
|
1878
2105
|
nextStep: shouldTerminate ? 'success' : 'retry',
|
|
@@ -1880,6 +2107,9 @@ class BaseAgent {
|
|
|
1880
2107
|
payloadChangeResult: currentStepPayloadChangeResult
|
|
1881
2108
|
})
|
|
1882
2109
|
};
|
|
2110
|
+
if (stepEntity) {
|
|
2111
|
+
stepEntity.PayloadAtEnd = JSON.stringify(mergedPayload);
|
|
2112
|
+
}
|
|
1883
2113
|
await this.finalizeStepEntity(stepEntity, subAgentResult.success, subAgentResult.agentRun?.ErrorMessage, outputData);
|
|
1884
2114
|
if (subAgentResult.agentRun?.FinalStep === 'Chat') {
|
|
1885
2115
|
return {
|
|
@@ -1901,9 +2131,6 @@ class BaseAgent {
|
|
|
1901
2131
|
role: 'user',
|
|
1902
2132
|
content: `Related sub-agent "${subAgentRequest.name}" completed:\n${JSON.stringify(subAgentSummary, null, 2)}`
|
|
1903
2133
|
});
|
|
1904
|
-
if (stepEntity) {
|
|
1905
|
-
stepEntity.PayloadAtEnd = JSON.stringify(mergedPayload);
|
|
1906
|
-
}
|
|
1907
2134
|
if (this._agentRun) {
|
|
1908
2135
|
this._agentRun.FinalPayloadObject = mergedPayload;
|
|
1909
2136
|
}
|
|
@@ -1965,6 +2192,72 @@ class BaseAgent {
|
|
|
1965
2192
|
return null;
|
|
1966
2193
|
}
|
|
1967
2194
|
}
|
|
2195
|
+
applySubAgentInputMapping(parentPayload, mappingConfig) {
|
|
2196
|
+
try {
|
|
2197
|
+
const mapping = JSON.parse(mappingConfig);
|
|
2198
|
+
const subAgentPayload = {};
|
|
2199
|
+
for (const [parentPath, subAgentPath] of Object.entries(mapping)) {
|
|
2200
|
+
let value;
|
|
2201
|
+
if (parentPath === '*') {
|
|
2202
|
+
value = parentPayload;
|
|
2203
|
+
}
|
|
2204
|
+
else {
|
|
2205
|
+
value = this.getValueFromPath(parentPayload, parentPath);
|
|
2206
|
+
}
|
|
2207
|
+
if (value !== undefined) {
|
|
2208
|
+
const pathParts = subAgentPath.split('.');
|
|
2209
|
+
let current = subAgentPayload;
|
|
2210
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
2211
|
+
const part = pathParts[i];
|
|
2212
|
+
if (!(part in current)) {
|
|
2213
|
+
current[part] = {};
|
|
2214
|
+
}
|
|
2215
|
+
current = current[part];
|
|
2216
|
+
}
|
|
2217
|
+
current[pathParts[pathParts.length - 1]] = value;
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
if (Object.keys(subAgentPayload).length === 0) {
|
|
2221
|
+
return null;
|
|
2222
|
+
}
|
|
2223
|
+
return subAgentPayload;
|
|
2224
|
+
}
|
|
2225
|
+
catch (error) {
|
|
2226
|
+
(0, core_1.LogError)(`Failed to parse SubAgentInputMapping: ${error.message}`);
|
|
2227
|
+
return null;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
prepareRelatedSubAgentContextMessage(parentPayload, contextPaths) {
|
|
2231
|
+
if (!contextPaths || contextPaths.length === 0) {
|
|
2232
|
+
return null;
|
|
2233
|
+
}
|
|
2234
|
+
if (contextPaths.includes('*')) {
|
|
2235
|
+
return {
|
|
2236
|
+
role: 'user',
|
|
2237
|
+
content: `Parent Agent Context:\n\n${JSON.stringify(parentPayload, null, 2)}`
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
const contextData = {};
|
|
2241
|
+
for (const path of contextPaths) {
|
|
2242
|
+
const value = this.getValueFromPath(parentPayload, path);
|
|
2243
|
+
if (value !== undefined) {
|
|
2244
|
+
contextData[path] = value;
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
if (Object.keys(contextData).length === 0) {
|
|
2248
|
+
return null;
|
|
2249
|
+
}
|
|
2250
|
+
const contextLines = Object.entries(contextData).map(([key, value]) => {
|
|
2251
|
+
const valueStr = typeof value === 'object'
|
|
2252
|
+
? JSON.stringify(value, null, 2)
|
|
2253
|
+
: String(value);
|
|
2254
|
+
return `${key}:\n${valueStr}`;
|
|
2255
|
+
});
|
|
2256
|
+
return {
|
|
2257
|
+
role: 'user',
|
|
2258
|
+
content: `Parent Agent Context:\n\n${contextLines.join('\n\n')}`
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
1968
2261
|
getValueFromPath(obj, path) {
|
|
1969
2262
|
const parts = path.split('.');
|
|
1970
2263
|
let current = obj;
|
|
@@ -2009,35 +2302,34 @@ class BaseAgent {
|
|
|
2009
2302
|
let progressMessage;
|
|
2010
2303
|
if (actions.length === 1) {
|
|
2011
2304
|
const aa = actions[0];
|
|
2012
|
-
progressMessage = `Executing
|
|
2305
|
+
progressMessage = `Executing **${aa.name}** action`;
|
|
2013
2306
|
if (aa.params && Object.keys(aa.params).length > 0) {
|
|
2014
2307
|
const paramsList = Object.entries(aa.params)
|
|
2015
2308
|
.map(([key, value]) => {
|
|
2016
|
-
const displayValue =
|
|
2017
|
-
|
|
2018
|
-
: String(value);
|
|
2019
|
-
return ` - \`${key}\`: ${displayValue}`;
|
|
2309
|
+
const displayValue = this.formatParamValueForMessage(value);
|
|
2310
|
+
return `• **${key}**: ${displayValue}`;
|
|
2020
2311
|
})
|
|
2021
2312
|
.join('\n');
|
|
2022
|
-
progressMessage +=
|
|
2313
|
+
progressMessage += ` with parameters:\n${paramsList}`;
|
|
2314
|
+
}
|
|
2315
|
+
else {
|
|
2316
|
+
progressMessage += '.';
|
|
2023
2317
|
}
|
|
2024
2318
|
}
|
|
2025
2319
|
else {
|
|
2026
|
-
progressMessage = `Executing
|
|
2027
|
-
|
|
2028
|
-
progressMessage += `\n\n• **${aa.name}**`;
|
|
2320
|
+
progressMessage = `Executing **${actions.length} actions** in parallel:\n\n` + actions.map((aa, index) => {
|
|
2321
|
+
let actionText = `${index + 1}. **${aa.name}**`;
|
|
2029
2322
|
if (aa.params && Object.keys(aa.params).length > 0) {
|
|
2030
2323
|
const paramsList = Object.entries(aa.params)
|
|
2031
2324
|
.map(([key, value]) => {
|
|
2032
|
-
const displayValue =
|
|
2033
|
-
|
|
2034
|
-
: String(value);
|
|
2035
|
-
return ` - \`${key}\`: ${displayValue}`;
|
|
2325
|
+
const displayValue = this.formatParamValueForMessage(value);
|
|
2326
|
+
return ` • **${key}**: ${displayValue}`;
|
|
2036
2327
|
})
|
|
2037
2328
|
.join('\n');
|
|
2038
|
-
|
|
2329
|
+
actionText += `\n${paramsList}`;
|
|
2039
2330
|
}
|
|
2040
|
-
|
|
2331
|
+
return actionText;
|
|
2332
|
+
}).join('\n\n');
|
|
2041
2333
|
}
|
|
2042
2334
|
params.onProgress?.({
|
|
2043
2335
|
step: 'action_execution',
|
|
@@ -2049,9 +2341,38 @@ class BaseAgent {
|
|
|
2049
2341
|
},
|
|
2050
2342
|
displayMode: 'live'
|
|
2051
2343
|
});
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2344
|
+
let actionMessage;
|
|
2345
|
+
if (actions.length === 1) {
|
|
2346
|
+
const aa = actions[0];
|
|
2347
|
+
actionMessage = `I'm executing the **${aa.name}** action`;
|
|
2348
|
+
if (aa.params && Object.keys(aa.params).length > 0) {
|
|
2349
|
+
const paramsList = Object.entries(aa.params)
|
|
2350
|
+
.map(([key, value]) => {
|
|
2351
|
+
const displayValue = this.formatParamValueForMessage(value);
|
|
2352
|
+
return `• **${key}**: ${displayValue}`;
|
|
2353
|
+
})
|
|
2354
|
+
.join('\n');
|
|
2355
|
+
actionMessage += ` with parameters:\n${paramsList}`;
|
|
2356
|
+
}
|
|
2357
|
+
else {
|
|
2358
|
+
actionMessage += '.';
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
else {
|
|
2362
|
+
actionMessage = `I'm executing **${actions.length} actions** in parallel:\n\n` + actions.map((aa, index) => {
|
|
2363
|
+
let actionText = `${index + 1}. **${aa.name}**`;
|
|
2364
|
+
if (aa.params && Object.keys(aa.params).length > 0) {
|
|
2365
|
+
const paramsList = Object.entries(aa.params)
|
|
2366
|
+
.map(([key, value]) => {
|
|
2367
|
+
const displayValue = this.formatParamValueForMessage(value);
|
|
2368
|
+
return ` • **${key}**: ${displayValue}`;
|
|
2369
|
+
})
|
|
2370
|
+
.join('\n');
|
|
2371
|
+
actionText += `\n${paramsList}`;
|
|
2372
|
+
}
|
|
2373
|
+
return actionText;
|
|
2374
|
+
}).join('\n\n');
|
|
2375
|
+
}
|
|
2055
2376
|
params.conversationMessages.push({
|
|
2056
2377
|
role: 'assistant',
|
|
2057
2378
|
content: actionMessage
|
|
@@ -2120,9 +2441,44 @@ class BaseAgent {
|
|
|
2120
2441
|
});
|
|
2121
2442
|
const failedActions = actionSummaries.filter(a => !a.success);
|
|
2122
2443
|
const resultsMessage = (failedActions.length > 0 ? `${failedActions.length} of ${actionSummaries.length} failed:` : `Action results:`) + `\n${JSON.stringify(actionSummaries, null, 2)}`;
|
|
2444
|
+
let metadata;
|
|
2445
|
+
const agentActionConfigs = actionResults
|
|
2446
|
+
.map(r => agentActions.find(aa => aa.ActionID === r.actionEntity.ID))
|
|
2447
|
+
.filter(aa => aa != null);
|
|
2448
|
+
if (agentActionConfigs.length > 0) {
|
|
2449
|
+
let minExpirationTurns = null;
|
|
2450
|
+
let expirationMode = 'None';
|
|
2451
|
+
let compactMode;
|
|
2452
|
+
let compactLength;
|
|
2453
|
+
let compactPromptId;
|
|
2454
|
+
for (const agentAction of agentActionConfigs) {
|
|
2455
|
+
if (agentAction.ResultExpirationTurns != null) {
|
|
2456
|
+
if (minExpirationTurns === null || agentAction.ResultExpirationTurns < minExpirationTurns) {
|
|
2457
|
+
minExpirationTurns = agentAction.ResultExpirationTurns;
|
|
2458
|
+
expirationMode = agentAction.ResultExpirationMode || 'None';
|
|
2459
|
+
compactMode = agentAction.CompactMode;
|
|
2460
|
+
compactLength = agentAction.CompactLength;
|
|
2461
|
+
compactPromptId = agentAction.CompactPromptID;
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
if (minExpirationTurns !== null && expirationMode !== 'None') {
|
|
2466
|
+
const currentStepCount = this._agentRun?.Steps?.length || 0;
|
|
2467
|
+
metadata = {
|
|
2468
|
+
turnAdded: currentStepCount,
|
|
2469
|
+
messageType: 'action-result',
|
|
2470
|
+
expirationTurns: minExpirationTurns,
|
|
2471
|
+
expirationMode: expirationMode,
|
|
2472
|
+
compactMode: compactMode,
|
|
2473
|
+
compactLength: compactLength,
|
|
2474
|
+
compactPromptId: compactPromptId
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2123
2478
|
params.conversationMessages.push({
|
|
2124
2479
|
role: 'user',
|
|
2125
|
-
content: resultsMessage
|
|
2480
|
+
content: resultsMessage,
|
|
2481
|
+
metadata: metadata
|
|
2126
2482
|
});
|
|
2127
2483
|
let finalPayload = currentPayload;
|
|
2128
2484
|
try {
|
|
@@ -2188,6 +2544,7 @@ class BaseAgent {
|
|
|
2188
2544
|
confidence: previousDecision.confidence,
|
|
2189
2545
|
previousPayload: previousDecision.previousPayload,
|
|
2190
2546
|
newPayload: previousDecision.newPayload || previousDecision.previousPayload,
|
|
2547
|
+
suggestedResponses: previousDecision.suggestedResponses
|
|
2191
2548
|
};
|
|
2192
2549
|
}
|
|
2193
2550
|
async createFailureResult(errorMessage, contextUser) {
|
|
@@ -2257,7 +2614,8 @@ class BaseAgent {
|
|
|
2257
2614
|
return {
|
|
2258
2615
|
success: finalStep.step === 'Success' || finalStep.step === 'Chat',
|
|
2259
2616
|
payload,
|
|
2260
|
-
agentRun: this._agentRun
|
|
2617
|
+
agentRun: this._agentRun,
|
|
2618
|
+
suggestedResponses: finalStep.suggestedResponses
|
|
2261
2619
|
};
|
|
2262
2620
|
}
|
|
2263
2621
|
calculateTokenStats() {
|
|
@@ -2318,6 +2676,236 @@ class BaseAgent {
|
|
|
2318
2676
|
}
|
|
2319
2677
|
return violations;
|
|
2320
2678
|
}
|
|
2679
|
+
async pruneAndCompactExpiredMessages(params, currentTurn) {
|
|
2680
|
+
const messagesToCompact = [];
|
|
2681
|
+
const messagesToRemove = [];
|
|
2682
|
+
for (let i = 0; i < params.conversationMessages.length; i++) {
|
|
2683
|
+
const msg = params.conversationMessages[i];
|
|
2684
|
+
if (!msg.metadata?.expirationTurns && msg.metadata?.expirationTurns !== 0) {
|
|
2685
|
+
continue;
|
|
2686
|
+
}
|
|
2687
|
+
if (msg.metadata.expirationMode === 'None') {
|
|
2688
|
+
continue;
|
|
2689
|
+
}
|
|
2690
|
+
const turnAdded = msg.metadata.turnAdded || 0;
|
|
2691
|
+
const turnsAlive = currentTurn - turnAdded;
|
|
2692
|
+
if (turnsAlive > msg.metadata.expirationTurns) {
|
|
2693
|
+
msg.metadata.isExpired = true;
|
|
2694
|
+
if (msg.metadata.expirationMode === 'Remove') {
|
|
2695
|
+
messagesToRemove.push(i);
|
|
2696
|
+
this.emitMessageLifecycleEvent({
|
|
2697
|
+
type: 'message-expired',
|
|
2698
|
+
turn: currentTurn,
|
|
2699
|
+
messageIndex: i,
|
|
2700
|
+
message: msg,
|
|
2701
|
+
reason: `Expired after ${turnsAlive} turns (limit: ${msg.metadata.expirationTurns})`
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
else if (msg.metadata.expirationMode === 'Compact') {
|
|
2705
|
+
if (msg.metadata.compactMode) {
|
|
2706
|
+
messagesToCompact.push({
|
|
2707
|
+
index: i,
|
|
2708
|
+
message: msg,
|
|
2709
|
+
metadata: {
|
|
2710
|
+
compactMode: msg.metadata.compactMode,
|
|
2711
|
+
compactLength: msg.metadata.compactLength || 500,
|
|
2712
|
+
compactPromptId: msg.metadata.compactPromptId || '',
|
|
2713
|
+
originalLength: typeof msg.content === 'string'
|
|
2714
|
+
? msg.content.length
|
|
2715
|
+
: JSON.stringify(msg.content).length
|
|
2716
|
+
}
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
const preserveOriginal = params.messageExpirationOverride?.preserveOriginalContent !== false;
|
|
2723
|
+
for (const item of messagesToCompact) {
|
|
2724
|
+
const originalContent = item.message.content;
|
|
2725
|
+
const compacted = await this.compactMessage(item.message, item.metadata, params);
|
|
2726
|
+
const originalTokens = this.estimateTokens(originalContent);
|
|
2727
|
+
const compactedTokens = this.estimateTokens(compacted);
|
|
2728
|
+
const tokensSaved = originalTokens - compactedTokens;
|
|
2729
|
+
params.conversationMessages[item.index] = {
|
|
2730
|
+
...item.message,
|
|
2731
|
+
content: compacted,
|
|
2732
|
+
metadata: {
|
|
2733
|
+
...item.message.metadata,
|
|
2734
|
+
wasCompacted: true,
|
|
2735
|
+
originalContent: preserveOriginal ? originalContent : undefined,
|
|
2736
|
+
originalLength: item.metadata.originalLength,
|
|
2737
|
+
tokensSaved,
|
|
2738
|
+
canExpand: preserveOriginal
|
|
2739
|
+
}
|
|
2740
|
+
};
|
|
2741
|
+
this.emitMessageLifecycleEvent({
|
|
2742
|
+
type: 'message-compacted',
|
|
2743
|
+
turn: currentTurn,
|
|
2744
|
+
messageIndex: item.index,
|
|
2745
|
+
message: params.conversationMessages[item.index],
|
|
2746
|
+
reason: `Compacted using ${item.metadata.compactMode} (saved ${tokensSaved} tokens)`,
|
|
2747
|
+
tokensSaved
|
|
2748
|
+
});
|
|
2749
|
+
}
|
|
2750
|
+
for (let i = messagesToRemove.length - 1; i >= 0; i--) {
|
|
2751
|
+
const index = messagesToRemove[i];
|
|
2752
|
+
const removed = params.conversationMessages.splice(index, 1)[0];
|
|
2753
|
+
this.emitMessageLifecycleEvent({
|
|
2754
|
+
type: 'message-removed',
|
|
2755
|
+
turn: currentTurn,
|
|
2756
|
+
messageIndex: index,
|
|
2757
|
+
message: removed,
|
|
2758
|
+
reason: 'Removed due to expiration'
|
|
2759
|
+
});
|
|
2760
|
+
}
|
|
2761
|
+
if (params.verbose && (messagesToCompact.length > 0 || messagesToRemove.length > 0)) {
|
|
2762
|
+
const totalSaved = messagesToCompact.reduce((sum, item) => {
|
|
2763
|
+
const msg = params.conversationMessages[item.index];
|
|
2764
|
+
return sum + (msg.metadata?.tokensSaved || 0);
|
|
2765
|
+
}, 0);
|
|
2766
|
+
console.log(`[Turn ${currentTurn}] Message pruning: ` +
|
|
2767
|
+
`${messagesToCompact.length} compacted (saved ~${totalSaved} tokens), ` +
|
|
2768
|
+
`${messagesToRemove.length} removed`);
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
async createCompactionStep(prompt, message, params) {
|
|
2772
|
+
if (!this._agentRun) {
|
|
2773
|
+
throw new Error('Cannot create compaction step: agent run not initialized');
|
|
2774
|
+
}
|
|
2775
|
+
const md = new core_1.Metadata();
|
|
2776
|
+
const step = await md.GetEntityObject('MJ: AI Agent Run Steps', params.contextUser);
|
|
2777
|
+
step.NewRecord();
|
|
2778
|
+
step.AgentRunID = this._agentRun.ID;
|
|
2779
|
+
step.StepType = 'Prompt';
|
|
2780
|
+
step.Status = 'Running';
|
|
2781
|
+
step.InputData = JSON.stringify({
|
|
2782
|
+
stepName: 'Message Compaction',
|
|
2783
|
+
description: `Compacting message using AI Summary (${message.metadata?.messageType || 'unknown'} from turn ${message.metadata?.turnAdded || 0})`,
|
|
2784
|
+
messageType: message.metadata?.messageType,
|
|
2785
|
+
turnAdded: message.metadata?.turnAdded,
|
|
2786
|
+
originalLength: message.metadata?.originalLength ||
|
|
2787
|
+
(typeof message.content === 'string' ? message.content.length : JSON.stringify(message.content).length),
|
|
2788
|
+
compactMode: 'AI Summary',
|
|
2789
|
+
promptId: prompt.ID,
|
|
2790
|
+
promptName: prompt.Name
|
|
2791
|
+
});
|
|
2792
|
+
await step.Save();
|
|
2793
|
+
return step;
|
|
2794
|
+
}
|
|
2795
|
+
async updateCompactionStep(step, result, message, params) {
|
|
2796
|
+
step.Status = result.success ? 'Completed' : 'Failed';
|
|
2797
|
+
const promptTokens = result.promptTokens || 0;
|
|
2798
|
+
const completionTokens = result.completionTokens || 0;
|
|
2799
|
+
step.OutputData = JSON.stringify({
|
|
2800
|
+
success: result.success,
|
|
2801
|
+
summaryLength: result.result?.summary?.length || 0,
|
|
2802
|
+
tokensSaved: message.metadata?.tokensSaved || 0,
|
|
2803
|
+
promptTokens,
|
|
2804
|
+
completionTokens,
|
|
2805
|
+
totalTokens: promptTokens + completionTokens,
|
|
2806
|
+
cost: result.cost
|
|
2807
|
+
});
|
|
2808
|
+
if (!result.success) {
|
|
2809
|
+
step.ErrorMessage = result.errorMessage || 'AI Summary compaction failed';
|
|
2810
|
+
}
|
|
2811
|
+
await step.Save();
|
|
2812
|
+
}
|
|
2813
|
+
async compactMessage(message, metadata, params) {
|
|
2814
|
+
const originalContent = typeof message.content === 'string'
|
|
2815
|
+
? message.content
|
|
2816
|
+
: JSON.stringify(message.content);
|
|
2817
|
+
switch (metadata.compactMode) {
|
|
2818
|
+
case 'First N Chars': {
|
|
2819
|
+
const length = metadata.compactLength;
|
|
2820
|
+
if (originalContent.length <= length) {
|
|
2821
|
+
return originalContent;
|
|
2822
|
+
}
|
|
2823
|
+
const truncated = originalContent.substring(0, length);
|
|
2824
|
+
return `${truncated}...\n\n[Compacted: showing first ${length} of ${originalContent.length} characters. Agent can request expansion if needed.]`;
|
|
2825
|
+
}
|
|
2826
|
+
case 'AI Summary': {
|
|
2827
|
+
try {
|
|
2828
|
+
const promptId = metadata.compactPromptId || this.getSystemDefaultCompactPromptId();
|
|
2829
|
+
const prompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.ID === promptId);
|
|
2830
|
+
if (!prompt) {
|
|
2831
|
+
console.warn(`Compact prompt ${promptId} not found, falling back to First N Chars`);
|
|
2832
|
+
return this.compactMessage(message, { ...metadata, compactMode: 'First N Chars' }, params);
|
|
2833
|
+
}
|
|
2834
|
+
const step = await this.createCompactionStep(prompt, message, params);
|
|
2835
|
+
const promptParams = new ai_core_plus_1.AIPromptParams();
|
|
2836
|
+
promptParams.prompt = prompt;
|
|
2837
|
+
promptParams.data = {
|
|
2838
|
+
originalContent,
|
|
2839
|
+
originalLength: metadata.originalLength,
|
|
2840
|
+
targetLength: metadata.compactLength || 500,
|
|
2841
|
+
messageType: message.metadata?.messageType || 'unknown',
|
|
2842
|
+
turnAdded: message.metadata?.turnAdded || 0
|
|
2843
|
+
};
|
|
2844
|
+
promptParams.contextUser = params.contextUser;
|
|
2845
|
+
const runner = new ai_prompts_1.AIPromptRunner();
|
|
2846
|
+
const result = await runner.ExecutePrompt(promptParams);
|
|
2847
|
+
await this.updateCompactionStep(step, result, message, params);
|
|
2848
|
+
if (!result.success || !result.result?.summary) {
|
|
2849
|
+
console.warn('AI summary failed, falling back to First N Chars');
|
|
2850
|
+
return this.compactMessage(message, { ...metadata, compactMode: 'First N Chars' }, params);
|
|
2851
|
+
}
|
|
2852
|
+
return `[AI Summary of ${metadata.originalLength} chars. Agent can request full expansion if needed.]\n\n${result.result.summary}`;
|
|
2853
|
+
}
|
|
2854
|
+
catch (error) {
|
|
2855
|
+
console.error('Error during AI summary:', error);
|
|
2856
|
+
return this.compactMessage(message, { ...metadata, compactMode: 'First N Chars' }, params);
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
default:
|
|
2860
|
+
return originalContent;
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
getSystemDefaultCompactPromptId() {
|
|
2864
|
+
const prompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Compact Agent Message');
|
|
2865
|
+
if (!prompt) {
|
|
2866
|
+
console.warn('System default compact prompt not found. Ensure "Compact Agent Message" prompt exists.');
|
|
2867
|
+
return '';
|
|
2868
|
+
}
|
|
2869
|
+
return prompt.ID;
|
|
2870
|
+
}
|
|
2871
|
+
estimateTokens(content) {
|
|
2872
|
+
const text = typeof content === 'string'
|
|
2873
|
+
? content
|
|
2874
|
+
: JSON.stringify(content);
|
|
2875
|
+
return Math.ceil(text.length / 4);
|
|
2876
|
+
}
|
|
2877
|
+
emitMessageLifecycleEvent(event) {
|
|
2878
|
+
if (this._messageLifecycleCallback) {
|
|
2879
|
+
this._messageLifecycleCallback(event);
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
executeExpandMessageStep(request, params, currentTurn) {
|
|
2883
|
+
const messageIndex = request.messageIndex;
|
|
2884
|
+
const reason = request.expandReason;
|
|
2885
|
+
if (messageIndex === undefined || messageIndex < 0 || messageIndex >= params.conversationMessages.length) {
|
|
2886
|
+
console.warn(`Cannot expand message: index ${messageIndex} out of bounds`);
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
const message = params.conversationMessages[messageIndex];
|
|
2890
|
+
if (!message.metadata?.canExpand || !message.metadata?.originalContent) {
|
|
2891
|
+
console.warn(`Cannot expand message at index ${messageIndex}: not expandable or no original content`);
|
|
2892
|
+
return;
|
|
2893
|
+
}
|
|
2894
|
+
message.content = message.metadata.originalContent;
|
|
2895
|
+
message.metadata.wasCompacted = false;
|
|
2896
|
+
message.metadata.canExpand = false;
|
|
2897
|
+
delete message.metadata.originalContent;
|
|
2898
|
+
this.emitMessageLifecycleEvent({
|
|
2899
|
+
type: 'message-expanded',
|
|
2900
|
+
turn: currentTurn,
|
|
2901
|
+
messageIndex,
|
|
2902
|
+
message,
|
|
2903
|
+
reason: reason || 'Agent requested expansion'
|
|
2904
|
+
});
|
|
2905
|
+
if (params.verbose) {
|
|
2906
|
+
console.log(`[Turn ${currentTurn}] Expanded message at index ${messageIndex}`);
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2321
2909
|
}
|
|
2322
2910
|
exports.BaseAgent = BaseAgent;
|
|
2323
2911
|
BaseAgent.MAX_VALIDATION_RETRIES = 10;
|