@memberjunction/ai-agents 2.49.0 → 2.51.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 +595 -3
- package/dist/AgentRunner.d.ts +2 -1
- package/dist/AgentRunner.d.ts.map +1 -1
- package/dist/AgentRunner.js +5 -2
- package/dist/AgentRunner.js.map +1 -1
- package/dist/agent-types/base-agent-type.d.ts +6 -0
- package/dist/agent-types/base-agent-type.d.ts.map +1 -0
- package/dist/agent-types/base-agent-type.js.map +1 -0
- package/dist/agent-types/index.d.ts +2 -1
- package/dist/agent-types/index.d.ts.map +1 -1
- package/dist/agent-types/index.js +4 -3
- package/dist/agent-types/index.js.map +1 -1
- package/dist/agent-types/{LoopAgentType.d.ts → loop-agent-type.d.ts} +4 -4
- package/dist/agent-types/loop-agent-type.d.ts.map +1 -0
- package/dist/agent-types/{LoopAgentType.js → loop-agent-type.js} +71 -42
- package/dist/agent-types/loop-agent-type.js.map +1 -0
- package/dist/base-agent.d.ts +50 -1
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +1085 -98
- package/dist/base-agent.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +33 -15
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/agent-types/LoopAgentType.d.ts.map +0 -1
- package/dist/agent-types/LoopAgentType.js.map +0 -1
- package/dist/base-agent-type.d.ts +0 -6
- package/dist/base-agent-type.d.ts.map +0 -1
- package/dist/base-agent-type.js.map +0 -1
- /package/dist/{base-agent-type.js → agent-types/base-agent-type.js} +0 -0
package/dist/base-agent.js
CHANGED
|
@@ -1,113 +1,236 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BaseAgent = void 0;
|
|
4
|
+
const core_1 = require("@memberjunction/core");
|
|
4
5
|
const ai_prompts_1 = require("@memberjunction/ai-prompts");
|
|
5
|
-
const base_agent_type_1 = require("./base-agent-type");
|
|
6
|
+
const base_agent_type_1 = require("./agent-types/base-agent-type");
|
|
6
7
|
const global_1 = require("@memberjunction/global");
|
|
7
8
|
const aiengine_1 = require("@memberjunction/aiengine");
|
|
8
9
|
const actions_1 = require("@memberjunction/actions");
|
|
10
|
+
const AgentRunner_1 = require("./AgentRunner");
|
|
9
11
|
class BaseAgent {
|
|
10
12
|
constructor() {
|
|
11
13
|
this._promptRunner = new ai_prompts_1.AIPromptRunner();
|
|
14
|
+
this._metadata = new core_1.Metadata();
|
|
15
|
+
this._runContext = null;
|
|
16
|
+
this._agentRun = null;
|
|
17
|
+
this._executionChain = [];
|
|
18
|
+
this._allProgressSteps = [];
|
|
19
|
+
this._subAgentRuns = [];
|
|
20
|
+
}
|
|
21
|
+
async getAgentRunSteps(contextUser) {
|
|
22
|
+
if (!this._agentRun)
|
|
23
|
+
return [];
|
|
24
|
+
const md = new core_1.Metadata();
|
|
25
|
+
const rv = new core_1.RunView();
|
|
26
|
+
const result = await rv.RunView({
|
|
27
|
+
EntityName: 'MJ: AI Agent Run Steps',
|
|
28
|
+
ExtraFilter: `AgentRunID = '${this._agentRun.ID}'`,
|
|
29
|
+
OrderBy: 'StepNumber',
|
|
30
|
+
ResultType: 'entity_object'
|
|
31
|
+
}, contextUser);
|
|
32
|
+
return result.Success ? result.Results : [];
|
|
33
|
+
}
|
|
34
|
+
wrapProgressCallback(originalCallback) {
|
|
35
|
+
if (!originalCallback)
|
|
36
|
+
return undefined;
|
|
37
|
+
return (progress) => {
|
|
38
|
+
this._allProgressSteps.push({
|
|
39
|
+
...progress,
|
|
40
|
+
timestamp: new Date(),
|
|
41
|
+
agentHierarchy: this._runContext?.agentHierarchy || [],
|
|
42
|
+
depth: this._runContext?.depth || 0
|
|
43
|
+
});
|
|
44
|
+
originalCallback(progress);
|
|
45
|
+
};
|
|
12
46
|
}
|
|
13
47
|
async Execute(params) {
|
|
14
48
|
try {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
errorMessage: `Agent '${params.agent.Name}' is not active. Current status: ${params.agent.Status}`
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
const agentType = engine.AgentTypes.find(at => at.ID === params.agent.TypeID);
|
|
25
|
-
if (!agentType) {
|
|
26
|
-
return {
|
|
27
|
-
nextStep: 'failed',
|
|
28
|
-
errorMessage: `Agent type not found for ID: ${params.agent.TypeID}`
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
const systemPrompt = engine.Prompts.find(p => p.ID === agentType.SystemPromptID);
|
|
32
|
-
if (!systemPrompt) {
|
|
33
|
-
return {
|
|
34
|
-
nextStep: 'failed',
|
|
35
|
-
errorMessage: `System prompt not found for agent type: ${agentType.Name}`
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
const agentPrompt = engine.AgentPrompts
|
|
39
|
-
.filter(ap => ap.AgentID === params.agent.ID && ap.Status === 'Active')
|
|
40
|
-
.sort((a, b) => a.ExecutionOrder - b.ExecutionOrder)[0];
|
|
41
|
-
if (!agentPrompt) {
|
|
42
|
-
return {
|
|
43
|
-
nextStep: 'failed',
|
|
44
|
-
errorMessage: `No prompts configured for agent: ${params.agent.Name}`
|
|
45
|
-
};
|
|
49
|
+
const wrappedParams = {
|
|
50
|
+
...params,
|
|
51
|
+
onProgress: this.wrapProgressCallback(params.onProgress)
|
|
52
|
+
};
|
|
53
|
+
if (params.cancellationToken?.aborted) {
|
|
54
|
+
return await this.createCancelledResult('Cancelled before execution started', params.contextUser);
|
|
46
55
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
wrappedParams.onProgress?.({
|
|
57
|
+
step: 'initialization',
|
|
58
|
+
percentage: 0,
|
|
59
|
+
message: this.formatHierarchicalMessage(`Initializing ${params.agent.Name} agent and preparing execution environment`)
|
|
60
|
+
});
|
|
61
|
+
await this.initializeAgentRun(wrappedParams);
|
|
62
|
+
await this.initializeEngines(params.contextUser);
|
|
63
|
+
if (params.cancellationToken?.aborted) {
|
|
64
|
+
return await this.createCancelledResult('Cancelled during initialization', params.contextUser);
|
|
53
65
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return
|
|
65
|
-
nextStep: 'failed',
|
|
66
|
-
errorMessage: errorMsg
|
|
67
|
-
};
|
|
66
|
+
wrappedParams.onProgress?.({
|
|
67
|
+
step: 'validation',
|
|
68
|
+
percentage: 10,
|
|
69
|
+
message: this.formatHierarchicalMessage('Validating agent configuration and loading prompts')
|
|
70
|
+
});
|
|
71
|
+
const validationResult = await this.validateAgentWithTracking(params.agent, params.contextUser);
|
|
72
|
+
if (validationResult)
|
|
73
|
+
return validationResult;
|
|
74
|
+
const config = await this.loadAgentConfiguration(params.agent);
|
|
75
|
+
if (!config.success) {
|
|
76
|
+
return await this.createFailureResult(config.errorMessage || 'Failed to load agent configuration', params.contextUser);
|
|
68
77
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
let continueExecution = true;
|
|
79
|
+
let currentNextStep = null;
|
|
80
|
+
let finalReturnValue = undefined;
|
|
81
|
+
let stepCount = 0;
|
|
82
|
+
while (continueExecution) {
|
|
83
|
+
if (params.cancellationToken?.aborted) {
|
|
84
|
+
return await this.createCancelledResult('Cancelled during execution', params.contextUser);
|
|
85
|
+
}
|
|
86
|
+
const stepResult = await this.executeNextStep(wrappedParams, config, currentNextStep);
|
|
87
|
+
stepCount++;
|
|
88
|
+
if (stepResult.terminate) {
|
|
89
|
+
continueExecution = false;
|
|
90
|
+
finalReturnValue = stepResult.returnValue;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
currentNextStep = stepResult.nextStep;
|
|
94
|
+
}
|
|
85
95
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
wrappedParams.onProgress?.({
|
|
97
|
+
step: 'finalization',
|
|
98
|
+
percentage: 95,
|
|
99
|
+
message: this.formatHierarchicalMessage('Finalizing agent execution')
|
|
100
|
+
});
|
|
101
|
+
return await this.finalizeAgentRun(finalReturnValue?.step || 'success', finalReturnValue, params.contextUser);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (params.cancellationToken?.aborted) {
|
|
105
|
+
return await this.createCancelledResult('Cancelled due to error during execution', params.contextUser);
|
|
95
106
|
}
|
|
96
|
-
|
|
107
|
+
return await this.createFailureResult(error.message, params.contextUser);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async initializeEngines(contextUser) {
|
|
111
|
+
await aiengine_1.AIEngine.Instance.Config(false, contextUser);
|
|
112
|
+
await actions_1.ActionEngineServer.Instance.Config(false, contextUser);
|
|
113
|
+
}
|
|
114
|
+
async validateAgent(agent) {
|
|
115
|
+
if (agent.Status !== 'Active') {
|
|
97
116
|
return {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
117
|
+
success: false,
|
|
118
|
+
finalStep: 'failed',
|
|
119
|
+
errorMessage: `Agent '${agent.Name}' is not active. Current status: ${agent.Status}`,
|
|
120
|
+
agentRun: this._agentRun,
|
|
121
|
+
executionTree: []
|
|
101
122
|
};
|
|
102
123
|
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
async loadAgentConfiguration(agent) {
|
|
127
|
+
const engine = aiengine_1.AIEngine.Instance;
|
|
128
|
+
const agentType = engine.AgentTypes.find(at => at.ID === agent.TypeID);
|
|
129
|
+
if (!agentType) {
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
errorMessage: `Agent type not found for ID: ${agent.TypeID}`
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const systemPrompt = engine.Prompts.find(p => p.ID === agentType.SystemPromptID);
|
|
136
|
+
if (!systemPrompt) {
|
|
137
|
+
return {
|
|
138
|
+
success: false,
|
|
139
|
+
errorMessage: `System prompt not found for agent type: ${agentType.Name}`
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const agentPrompt = engine.AgentPrompts
|
|
143
|
+
.filter(ap => ap.AgentID === agent.ID && ap.Status === 'Active')
|
|
144
|
+
.sort((a, b) => a.ExecutionOrder - b.ExecutionOrder)[0];
|
|
145
|
+
if (!agentPrompt) {
|
|
146
|
+
return {
|
|
147
|
+
success: false,
|
|
148
|
+
errorMessage: `No prompts configured for agent: ${agent.Name}`
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const childPrompt = engine.Prompts.find(p => p.ID === agentPrompt.PromptID);
|
|
152
|
+
if (!childPrompt) {
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
errorMessage: `Child prompt not found for ID: ${agentPrompt.PromptID}`
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (!agentType.AgentPromptPlaceholder) {
|
|
159
|
+
return {
|
|
160
|
+
success: false,
|
|
161
|
+
errorMessage: `Agent type '${agentType.Name}' does not have AgentPromptPlaceholder configured.`
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
success: true,
|
|
166
|
+
agentType,
|
|
167
|
+
systemPrompt,
|
|
168
|
+
childPrompt
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async preparePromptParams(agentType, systemPrompt, childPrompt, params) {
|
|
172
|
+
const contextData = await this.gatherContextData(params.agent, params.contextUser);
|
|
173
|
+
const promptParams = new ai_prompts_1.AIPromptParams();
|
|
174
|
+
promptParams.prompt = systemPrompt;
|
|
175
|
+
promptParams.data = contextData;
|
|
176
|
+
promptParams.contextUser = params.contextUser;
|
|
177
|
+
promptParams.conversationMessages = params.conversationMessages;
|
|
178
|
+
promptParams.templateMessageRole = 'system';
|
|
179
|
+
promptParams.childPrompts = [
|
|
180
|
+
new ai_prompts_1.ChildPromptParam({
|
|
181
|
+
prompt: childPrompt,
|
|
182
|
+
data: contextData,
|
|
183
|
+
contextUser: params.contextUser,
|
|
184
|
+
conversationMessages: params.conversationMessages,
|
|
185
|
+
templateMessageRole: 'user'
|
|
186
|
+
}, agentType.AgentPromptPlaceholder)
|
|
187
|
+
];
|
|
188
|
+
return promptParams;
|
|
189
|
+
}
|
|
190
|
+
async executePrompt(promptParams) {
|
|
191
|
+
return await this._promptRunner.ExecutePrompt(promptParams);
|
|
192
|
+
}
|
|
193
|
+
async processNextStep(params, agentType, promptResult) {
|
|
194
|
+
let agentTypeInstance;
|
|
195
|
+
try {
|
|
196
|
+
agentTypeInstance = await this.getAgentTypeInstance(agentType);
|
|
197
|
+
}
|
|
103
198
|
catch (error) {
|
|
104
199
|
return {
|
|
105
|
-
|
|
106
|
-
errorMessage: error.message
|
|
200
|
+
step: 'failed',
|
|
201
|
+
errorMessage: error.message
|
|
107
202
|
};
|
|
108
203
|
}
|
|
204
|
+
const nextStep = await agentTypeInstance.DetermineNextStep(promptResult);
|
|
205
|
+
return nextStep;
|
|
206
|
+
}
|
|
207
|
+
createActionResultMessage(actions, results) {
|
|
208
|
+
const resultSummary = actions.map((action, index) => {
|
|
209
|
+
const result = results[index];
|
|
210
|
+
const outputParams = result.Params?.filter((p) => p.Type === 'Output' || p.Type === 'Both') || [];
|
|
211
|
+
return {
|
|
212
|
+
actionName: action.name,
|
|
213
|
+
success: result.Success,
|
|
214
|
+
resultCode: result.Result?.Code || 'N/A',
|
|
215
|
+
message: result.Message || null,
|
|
216
|
+
outputs: outputParams.reduce((acc, param) => {
|
|
217
|
+
acc[param.Name] = param.Value;
|
|
218
|
+
return acc;
|
|
219
|
+
}, {})
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
return {
|
|
223
|
+
role: 'user',
|
|
224
|
+
content: `Action results:\n${JSON.stringify(resultSummary, null, 2)}`
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
createSubAgentResultMessage(subAgent, result) {
|
|
228
|
+
return {
|
|
229
|
+
role: 'user',
|
|
230
|
+
content: `Sub-agent '${subAgent.name}' result:\n${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`
|
|
231
|
+
};
|
|
109
232
|
}
|
|
110
|
-
async gatherContextData(agent,
|
|
233
|
+
async gatherContextData(agent, _contextUser) {
|
|
111
234
|
try {
|
|
112
235
|
const engine = aiengine_1.AIEngine.Instance;
|
|
113
236
|
const subAgents = engine.Agents.filter(a => a.ParentID === agent.ID)
|
|
@@ -119,21 +242,9 @@ class BaseAgent {
|
|
|
119
242
|
agentName: agent.Name,
|
|
120
243
|
agentDescription: agent.Description,
|
|
121
244
|
subAgentCount: subAgents.length,
|
|
122
|
-
subAgentDetails:
|
|
123
|
-
return {
|
|
124
|
-
ID: sa.ID,
|
|
125
|
-
Name: sa.Name,
|
|
126
|
-
Description: sa.Description
|
|
127
|
-
};
|
|
128
|
-
}), null, 2),
|
|
245
|
+
subAgentDetails: this.formatSubAgentDetails(subAgents),
|
|
129
246
|
actionCount: actions.length,
|
|
130
|
-
actionDetails:
|
|
131
|
-
return {
|
|
132
|
-
ID: action.ID,
|
|
133
|
-
Name: action.Name,
|
|
134
|
-
Description: action.Description,
|
|
135
|
-
};
|
|
136
|
-
}), null, 2),
|
|
247
|
+
actionDetails: this.formatActionDetails(activeActions),
|
|
137
248
|
};
|
|
138
249
|
return contextData;
|
|
139
250
|
}
|
|
@@ -151,6 +262,882 @@ class BaseAgent {
|
|
|
151
262
|
}
|
|
152
263
|
return instance;
|
|
153
264
|
}
|
|
265
|
+
async ExecuteActions(actions, contextUser) {
|
|
266
|
+
try {
|
|
267
|
+
const actionEngine = actions_1.ActionEngineServer.Instance;
|
|
268
|
+
const actionPromises = actions.map(async (action) => {
|
|
269
|
+
const actionEntity = actionEngine.Actions.find(a => a.ID === action.id || a.Name === action.name);
|
|
270
|
+
if (!actionEntity) {
|
|
271
|
+
throw new Error(`Action not found: ${action.name || action.id}`);
|
|
272
|
+
}
|
|
273
|
+
const actionParams = Object.entries(action.params || {}).map(([key, value]) => ({
|
|
274
|
+
Name: key,
|
|
275
|
+
Value: value,
|
|
276
|
+
Type: 'Input'
|
|
277
|
+
}));
|
|
278
|
+
const result = await actionEngine.RunAction({
|
|
279
|
+
Action: actionEntity,
|
|
280
|
+
Params: actionParams,
|
|
281
|
+
ContextUser: contextUser,
|
|
282
|
+
Filters: [],
|
|
283
|
+
SkipActionLog: false
|
|
284
|
+
});
|
|
285
|
+
if (!result.Success) {
|
|
286
|
+
throw new Error(`Action '${action.name}' failed: ${result.Message || 'Unknown error'}`);
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
});
|
|
290
|
+
return await Promise.all(actionPromises);
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
throw new Error(`Error executing actions: ${error.message}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
async ExecuteSubAgent(subAgentRequest, conversationMessages, contextUser, cancellationToken, onProgress, onStreaming) {
|
|
297
|
+
try {
|
|
298
|
+
const engine = aiengine_1.AIEngine.Instance;
|
|
299
|
+
const subAgent = engine.Agents.find(a => a.ID === subAgentRequest.id || a.Name === subAgentRequest.name);
|
|
300
|
+
if (!subAgent) {
|
|
301
|
+
throw new Error(`Sub-agent not found: ${subAgentRequest.name || subAgentRequest.id}`);
|
|
302
|
+
}
|
|
303
|
+
const runner = new AgentRunner_1.AgentRunner();
|
|
304
|
+
const subAgentMessages = [
|
|
305
|
+
...conversationMessages,
|
|
306
|
+
{
|
|
307
|
+
role: 'user',
|
|
308
|
+
content: subAgentRequest.message
|
|
309
|
+
}
|
|
310
|
+
];
|
|
311
|
+
const result = await runner.RunAgent({
|
|
312
|
+
agent: subAgent,
|
|
313
|
+
conversationMessages: subAgentMessages,
|
|
314
|
+
contextUser: contextUser,
|
|
315
|
+
cancellationToken: cancellationToken,
|
|
316
|
+
onProgress: onProgress,
|
|
317
|
+
onStreaming: onStreaming,
|
|
318
|
+
parentAgentHierarchy: this._runContext?.agentHierarchy,
|
|
319
|
+
parentDepth: this._runContext?.depth
|
|
320
|
+
});
|
|
321
|
+
if (!result.success) {
|
|
322
|
+
throw new Error(`Sub-agent '${subAgentRequest.name}' failed: ${result.errorMessage || 'Unknown error'}`);
|
|
323
|
+
}
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
throw new Error(`Error executing sub-agent: ${error.message}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
formatSubAgentDetails(subAgents) {
|
|
331
|
+
return JSON.stringify(subAgents.map(sa => ({
|
|
332
|
+
ID: sa.ID,
|
|
333
|
+
Name: sa.Name,
|
|
334
|
+
Description: sa.Description,
|
|
335
|
+
Type: sa.TypeID ? this.getAgentTypeName(sa.TypeID) : 'Unknown',
|
|
336
|
+
Status: sa.Status,
|
|
337
|
+
ExecutionMode: sa.ExecutionMode,
|
|
338
|
+
ExecutionOrder: sa.ExecutionOrder
|
|
339
|
+
})), null, 2);
|
|
340
|
+
}
|
|
341
|
+
formatActionDetails(actions) {
|
|
342
|
+
return JSON.stringify(actions.map(action => ({
|
|
343
|
+
ID: action.ID,
|
|
344
|
+
Name: action.Name,
|
|
345
|
+
Description: action.Description,
|
|
346
|
+
Parameters: {
|
|
347
|
+
Input: action.Params
|
|
348
|
+
.filter(p => p.Type.trim().toLowerCase() === 'input' || p.Type.trim().toLowerCase() === 'both')
|
|
349
|
+
.map(param => this.formatActionParameter(param)),
|
|
350
|
+
Output: action.Params
|
|
351
|
+
.filter(p => p.Type.trim().toLowerCase() === 'output' || p.Type.trim().toLowerCase() === 'both')
|
|
352
|
+
.map(param => this.formatActionParameter(param))
|
|
353
|
+
},
|
|
354
|
+
ResultCodes: action.ResultCodes.map(rc => ({
|
|
355
|
+
Code: rc.ResultCode,
|
|
356
|
+
IsSuccess: rc.IsSuccess,
|
|
357
|
+
Description: rc.Description || 'No description provided',
|
|
358
|
+
Usage: this.inferResultCodeUsage(rc.ResultCode, rc.IsSuccess)
|
|
359
|
+
})),
|
|
360
|
+
Category: action.CategoryID ? this.getActionCategoryName(action.CategoryID) : null,
|
|
361
|
+
Status: action.Status
|
|
362
|
+
})), null, 2);
|
|
363
|
+
}
|
|
364
|
+
formatActionParameter(param) {
|
|
365
|
+
return {
|
|
366
|
+
Name: param.Name,
|
|
367
|
+
Type: param.Type,
|
|
368
|
+
IsRequired: param.IsRequired,
|
|
369
|
+
IsArray: param.IsArray,
|
|
370
|
+
DefaultValue: param.DefaultValue,
|
|
371
|
+
Description: param.Description,
|
|
372
|
+
ValueType: param.ValueType
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
getAgentTypeName(typeID) {
|
|
376
|
+
const agentType = aiengine_1.AIEngine.Instance.AgentTypes.find(at => at.ID === typeID);
|
|
377
|
+
return agentType?.Name || 'Unknown';
|
|
378
|
+
}
|
|
379
|
+
getValueListItems(valueListID) {
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
getActionCategoryName(categoryID) {
|
|
383
|
+
return 'General';
|
|
384
|
+
}
|
|
385
|
+
inferResultCodeUsage(resultCode, isSuccess) {
|
|
386
|
+
if (resultCode === 'SUCCESS') {
|
|
387
|
+
return 'Returned when the action completes successfully';
|
|
388
|
+
}
|
|
389
|
+
else if (resultCode === 'FAILED') {
|
|
390
|
+
return 'Generic failure - check error message for details';
|
|
391
|
+
}
|
|
392
|
+
else if (resultCode.includes('MISSING_PARAMETERS')) {
|
|
393
|
+
return 'Returned when required parameters are not provided';
|
|
394
|
+
}
|
|
395
|
+
else if (resultCode.includes('INVALID')) {
|
|
396
|
+
return 'Returned when input validation fails';
|
|
397
|
+
}
|
|
398
|
+
else if (resultCode.includes('NOT_FOUND')) {
|
|
399
|
+
return 'Returned when the requested resource cannot be found';
|
|
400
|
+
}
|
|
401
|
+
else if (resultCode.includes('TIMEOUT')) {
|
|
402
|
+
return 'Returned when the operation times out';
|
|
403
|
+
}
|
|
404
|
+
else if (resultCode.includes('PERMISSION') || resultCode.includes('UNAUTHORIZED')) {
|
|
405
|
+
return 'Returned when permission is denied';
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
return isSuccess
|
|
409
|
+
? 'Specific success condition - see description'
|
|
410
|
+
: 'Specific error condition - see description';
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
async initializeAgentRun(params) {
|
|
414
|
+
this._agentRun = await this._metadata.GetEntityObject('MJ: AI Agent Runs', params.contextUser);
|
|
415
|
+
this._agentRun.AgentID = params.agent.ID;
|
|
416
|
+
this._agentRun.Status = 'Running';
|
|
417
|
+
this._agentRun.StartedAt = new Date();
|
|
418
|
+
this._agentRun.UserID = params.contextUser?.ID || null;
|
|
419
|
+
this._agentRun.ParentRunID = null;
|
|
420
|
+
if (!await this._agentRun.Save()) {
|
|
421
|
+
throw new Error('Failed to create agent run record');
|
|
422
|
+
}
|
|
423
|
+
this._runContext = {
|
|
424
|
+
currentStepIndex: 0,
|
|
425
|
+
parentRunStack: [],
|
|
426
|
+
agentHierarchy: params.parentAgentHierarchy
|
|
427
|
+
? [...params.parentAgentHierarchy, params.agent.Name || 'Unknown Agent']
|
|
428
|
+
: [params.agent.Name || 'Unknown Agent'],
|
|
429
|
+
depth: params.parentDepth !== undefined ? params.parentDepth + 1 : 0,
|
|
430
|
+
conversationId: undefined,
|
|
431
|
+
userId: params.contextUser?.ID,
|
|
432
|
+
agentState: {}
|
|
433
|
+
};
|
|
434
|
+
this._executionChain = [];
|
|
435
|
+
this._allProgressSteps = [];
|
|
436
|
+
}
|
|
437
|
+
async validateAgentWithTracking(agent, contextUser) {
|
|
438
|
+
const startTime = new Date();
|
|
439
|
+
try {
|
|
440
|
+
const validationResult = await this.validateAgent(agent);
|
|
441
|
+
if (validationResult) {
|
|
442
|
+
const stepEntity = await this.createStepEntity('validation', 'Agent Validation', contextUser);
|
|
443
|
+
const executionResult = {
|
|
444
|
+
type: 'validation',
|
|
445
|
+
validationTarget: 'agent configuration',
|
|
446
|
+
result: { valid: false, errors: [validationResult.errorMessage || 'Validation failed'] }
|
|
447
|
+
};
|
|
448
|
+
const nextStepDecision = {
|
|
449
|
+
decision: 'failed',
|
|
450
|
+
reasoning: 'Agent validation failed',
|
|
451
|
+
nextStepDetails: { type: 'complete' }
|
|
452
|
+
};
|
|
453
|
+
this._executionChain.push({
|
|
454
|
+
stepEntity,
|
|
455
|
+
executionType: 'validation',
|
|
456
|
+
executionResult,
|
|
457
|
+
nextStepDecision,
|
|
458
|
+
startTime,
|
|
459
|
+
endTime: new Date(),
|
|
460
|
+
durationMs: new Date().getTime() - startTime.getTime()
|
|
461
|
+
});
|
|
462
|
+
await this.finalizeStepEntity(stepEntity, false, validationResult.errorMessage);
|
|
463
|
+
return await this.createFailureResult(validationResult.errorMessage || 'Validation failed', contextUser);
|
|
464
|
+
}
|
|
465
|
+
const stepEntity = await this.createStepEntity('validation', 'Agent Validation', contextUser);
|
|
466
|
+
const executionResult = {
|
|
467
|
+
type: 'validation',
|
|
468
|
+
validationTarget: 'agent configuration',
|
|
469
|
+
result: { valid: true }
|
|
470
|
+
};
|
|
471
|
+
const nextStepDecision = {
|
|
472
|
+
decision: 'success',
|
|
473
|
+
reasoning: 'Agent validation passed',
|
|
474
|
+
nextStepDetails: { type: 'prompt', promptId: agent.ID, promptName: 'Initial Prompt' }
|
|
475
|
+
};
|
|
476
|
+
this._executionChain.push({
|
|
477
|
+
stepEntity,
|
|
478
|
+
executionType: 'validation',
|
|
479
|
+
executionResult,
|
|
480
|
+
nextStepDecision,
|
|
481
|
+
startTime,
|
|
482
|
+
endTime: new Date(),
|
|
483
|
+
durationMs: new Date().getTime() - startTime.getTime()
|
|
484
|
+
});
|
|
485
|
+
await this.finalizeStepEntity(stepEntity, true);
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
catch (error) {
|
|
489
|
+
return await this.createFailureResult(`Validation error: ${error.message}`, contextUser);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
async createStepEntity(stepType, stepName, contextUser, targetId, inputData) {
|
|
493
|
+
const stepEntity = await this._metadata.GetEntityObject('MJ: AI Agent Run Steps', contextUser);
|
|
494
|
+
stepEntity.AgentRunID = this._agentRun.ID;
|
|
495
|
+
stepEntity.StepNumber = this._runContext.currentStepIndex + 1;
|
|
496
|
+
stepEntity.StepType = stepType;
|
|
497
|
+
stepEntity.StepName = this.formatHierarchicalMessage(stepName);
|
|
498
|
+
stepEntity.TargetID = targetId || null;
|
|
499
|
+
stepEntity.Status = 'Running';
|
|
500
|
+
stepEntity.StartedAt = new Date();
|
|
501
|
+
if (inputData) {
|
|
502
|
+
stepEntity.InputData = JSON.stringify({
|
|
503
|
+
...inputData,
|
|
504
|
+
context: {
|
|
505
|
+
agentHierarchy: this._runContext.agentHierarchy,
|
|
506
|
+
depth: this._runContext.depth,
|
|
507
|
+
stepNumber: stepEntity.StepNumber
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
if (!await stepEntity.Save()) {
|
|
512
|
+
throw new Error(`Failed to create agent run step record: ${JSON.stringify(stepEntity.LatestResult)}`);
|
|
513
|
+
}
|
|
514
|
+
this._runContext.currentStepIndex++;
|
|
515
|
+
return stepEntity;
|
|
516
|
+
}
|
|
517
|
+
async finalizeStepEntity(stepEntity, success, errorMessage, outputData) {
|
|
518
|
+
stepEntity.Status = success ? 'Completed' : 'Failed';
|
|
519
|
+
stepEntity.CompletedAt = new Date();
|
|
520
|
+
stepEntity.Success = success;
|
|
521
|
+
stepEntity.ErrorMessage = errorMessage || null;
|
|
522
|
+
if (outputData) {
|
|
523
|
+
stepEntity.OutputData = JSON.stringify({
|
|
524
|
+
...outputData,
|
|
525
|
+
context: {
|
|
526
|
+
success,
|
|
527
|
+
durationMs: stepEntity.CompletedAt.getTime() - stepEntity.StartedAt.getTime(),
|
|
528
|
+
errorMessage
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
if (!await stepEntity.Save()) {
|
|
533
|
+
console.error('Failed to update agent run step record');
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
formatHierarchicalMessage(baseMessage) {
|
|
537
|
+
if (this._runContext && this._runContext.depth > 0) {
|
|
538
|
+
const breadcrumb = this._runContext.agentHierarchy
|
|
539
|
+
.slice(1)
|
|
540
|
+
.join(' → ');
|
|
541
|
+
return breadcrumb ? `${breadcrumb}: ${baseMessage}` : baseMessage;
|
|
542
|
+
}
|
|
543
|
+
return baseMessage;
|
|
544
|
+
}
|
|
545
|
+
async executeNextStep(params, config, previousDecision) {
|
|
546
|
+
if (!previousDecision) {
|
|
547
|
+
return await this.executePromptStep(params, config);
|
|
548
|
+
}
|
|
549
|
+
switch (previousDecision.step) {
|
|
550
|
+
case 'retry':
|
|
551
|
+
return await this.executePromptStep(params, config, previousDecision);
|
|
552
|
+
case 'sub-agent':
|
|
553
|
+
return await this.executeSubAgentStep(params, previousDecision.subAgent);
|
|
554
|
+
case 'actions':
|
|
555
|
+
return await this.executeActionsStep(params, previousDecision.actions);
|
|
556
|
+
case 'chat':
|
|
557
|
+
return await this.executeChatStep(params, previousDecision.userMessage);
|
|
558
|
+
case 'success':
|
|
559
|
+
case 'failed':
|
|
560
|
+
return { terminate: true, returnValue: previousDecision.returnValue };
|
|
561
|
+
default:
|
|
562
|
+
throw new Error(`Unsupported next step: ${previousDecision.step}`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
async executePromptStep(params, config, retryContext) {
|
|
566
|
+
const startTime = new Date();
|
|
567
|
+
const inputData = {
|
|
568
|
+
promptId: config.childPrompt?.ID,
|
|
569
|
+
promptName: config.childPrompt?.Name,
|
|
570
|
+
isRetry: !!retryContext,
|
|
571
|
+
retryContext: retryContext ? {
|
|
572
|
+
reason: retryContext.retryReason,
|
|
573
|
+
instructions: retryContext.retryInstructions
|
|
574
|
+
} : undefined,
|
|
575
|
+
conversationMessages: params.conversationMessages,
|
|
576
|
+
agentState: this._runContext?.agentState
|
|
577
|
+
};
|
|
578
|
+
const stepEntity = await this.createStepEntity('prompt', 'Execute Agent Prompt', params.contextUser, config.childPrompt?.ID, inputData);
|
|
579
|
+
try {
|
|
580
|
+
const isRetry = !!retryContext;
|
|
581
|
+
const promptMessage = isRetry
|
|
582
|
+
? `Re-executing agent prompt with additional context from ${retryContext.retryReason || 'previous actions'}`
|
|
583
|
+
: `Executing agent's initial prompt to analyze your request`;
|
|
584
|
+
params.onProgress?.({
|
|
585
|
+
step: 'prompt_execution',
|
|
586
|
+
percentage: 30,
|
|
587
|
+
message: this.formatHierarchicalMessage(promptMessage),
|
|
588
|
+
metadata: {
|
|
589
|
+
promptId: config.childPrompt?.ID,
|
|
590
|
+
isRetry,
|
|
591
|
+
promptName: config.childPrompt?.Name
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
const promptParams = await this.preparePromptParams(config.agentType, config.systemPrompt, config.childPrompt, params);
|
|
595
|
+
promptParams.cancellationToken = params.cancellationToken;
|
|
596
|
+
promptParams.onStreaming = params.onStreaming ? (chunk) => {
|
|
597
|
+
params.onStreaming({
|
|
598
|
+
...chunk,
|
|
599
|
+
stepType: 'prompt',
|
|
600
|
+
stepEntityId: stepEntity.ID
|
|
601
|
+
});
|
|
602
|
+
} : undefined;
|
|
603
|
+
const promptResult = await this.executePrompt(promptParams);
|
|
604
|
+
if (params.cancellationToken?.aborted) {
|
|
605
|
+
await this.finalizeStepEntity(stepEntity, false, 'Cancelled during prompt execution');
|
|
606
|
+
return { terminate: true, returnValue: await this.createCancelledResult('Cancelled during prompt execution', params.contextUser) };
|
|
607
|
+
}
|
|
608
|
+
const executionResult = {
|
|
609
|
+
type: 'prompt',
|
|
610
|
+
promptId: config.childPrompt.ID,
|
|
611
|
+
promptName: config.childPrompt.Name,
|
|
612
|
+
result: promptResult
|
|
613
|
+
};
|
|
614
|
+
params.onProgress?.({
|
|
615
|
+
step: 'decision_processing',
|
|
616
|
+
percentage: 70,
|
|
617
|
+
message: this.formatHierarchicalMessage('Analyzing response and determining next steps')
|
|
618
|
+
});
|
|
619
|
+
const nextStep = await this.processNextStep(params, config.agentType, promptResult);
|
|
620
|
+
const nextStepDecision = {
|
|
621
|
+
decision: nextStep.step,
|
|
622
|
+
reasoning: this.getNextStepReasoning(nextStep),
|
|
623
|
+
nextStepDetails: this.getNextStepDetails(nextStep)
|
|
624
|
+
};
|
|
625
|
+
this._executionChain.push({
|
|
626
|
+
stepEntity,
|
|
627
|
+
executionType: 'prompt',
|
|
628
|
+
executionResult,
|
|
629
|
+
nextStepDecision,
|
|
630
|
+
startTime,
|
|
631
|
+
endTime: new Date(),
|
|
632
|
+
durationMs: new Date().getTime() - startTime.getTime()
|
|
633
|
+
});
|
|
634
|
+
const outputData = {
|
|
635
|
+
promptResult: {
|
|
636
|
+
success: promptResult.success,
|
|
637
|
+
llmResponse: promptResult.llmResponse,
|
|
638
|
+
modelUsed: promptResult.runInfo?.modelName,
|
|
639
|
+
tokensUsed: promptResult.runInfo?.promptRun?.TotalTokensUsed,
|
|
640
|
+
totalCost: promptResult.runInfo?.promptRun?.TotalCost
|
|
641
|
+
},
|
|
642
|
+
nextStep: {
|
|
643
|
+
decision: nextStep.step,
|
|
644
|
+
reasoning: nextStepDecision.reasoning
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
await this.finalizeStepEntity(stepEntity, promptResult.success, promptResult.success ? undefined : promptResult.errorMessage, outputData);
|
|
648
|
+
if (nextStep.step === 'chat') {
|
|
649
|
+
return { terminate: true, returnValue: nextStep };
|
|
650
|
+
}
|
|
651
|
+
else if (nextStep.step === 'success' || nextStep.step === 'failed') {
|
|
652
|
+
return { terminate: true, returnValue: nextStep.returnValue };
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
return { terminate: false, nextStep };
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
await this.finalizeStepEntity(stepEntity, false, error.message);
|
|
660
|
+
throw error;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
async executeSubAgentStep(params, subAgentRequest) {
|
|
664
|
+
if (params.cancellationToken?.aborted) {
|
|
665
|
+
throw new Error('Cancelled before sub-agent execution');
|
|
666
|
+
}
|
|
667
|
+
params.onProgress?.({
|
|
668
|
+
step: 'subagent_execution',
|
|
669
|
+
percentage: 60,
|
|
670
|
+
message: this.formatHierarchicalMessage(`Delegating to ${subAgentRequest.name} agent`),
|
|
671
|
+
metadata: {
|
|
672
|
+
subAgentId: subAgentRequest.id,
|
|
673
|
+
subAgentName: subAgentRequest.name,
|
|
674
|
+
reason: subAgentRequest.message
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
params.conversationMessages.push({
|
|
678
|
+
role: 'assistant',
|
|
679
|
+
content: `I'm delegating this task to the "${subAgentRequest.name}" agent.\n\nReason: ${subAgentRequest.message}`
|
|
680
|
+
});
|
|
681
|
+
const startTime = new Date();
|
|
682
|
+
const inputData = {
|
|
683
|
+
subAgentId: subAgentRequest.id,
|
|
684
|
+
subAgentName: subAgentRequest.name,
|
|
685
|
+
message: subAgentRequest.message,
|
|
686
|
+
terminateAfter: subAgentRequest.terminateAfter,
|
|
687
|
+
conversationMessages: params.conversationMessages,
|
|
688
|
+
parentAgentHierarchy: this._runContext?.agentHierarchy
|
|
689
|
+
};
|
|
690
|
+
const stepEntity = await this.createStepEntity('subagent', `Execute Sub-Agent: ${subAgentRequest.name}`, params.contextUser, subAgentRequest.id, inputData);
|
|
691
|
+
try {
|
|
692
|
+
const subAgentResult = await this.ExecuteSubAgent(subAgentRequest, params.conversationMessages, params.contextUser, params.cancellationToken, params.onProgress ? (progress) => {
|
|
693
|
+
params.onProgress(progress);
|
|
694
|
+
} : undefined, params.onStreaming ? (chunk) => {
|
|
695
|
+
params.onStreaming({
|
|
696
|
+
...chunk,
|
|
697
|
+
stepType: 'subagent',
|
|
698
|
+
stepEntityId: stepEntity.ID
|
|
699
|
+
});
|
|
700
|
+
} : undefined);
|
|
701
|
+
if (params.cancellationToken?.aborted) {
|
|
702
|
+
await this.finalizeStepEntity(stepEntity, false, 'Cancelled during sub-agent execution');
|
|
703
|
+
throw new Error('Cancelled during sub-agent execution');
|
|
704
|
+
}
|
|
705
|
+
const executionResult = {
|
|
706
|
+
type: 'sub-agent',
|
|
707
|
+
subAgentId: subAgentRequest.id,
|
|
708
|
+
subAgentName: subAgentRequest.name,
|
|
709
|
+
result: subAgentResult
|
|
710
|
+
};
|
|
711
|
+
this._subAgentRuns.push(subAgentResult);
|
|
712
|
+
const shouldTerminate = subAgentRequest.terminateAfter;
|
|
713
|
+
const nextStepType = subAgentResult.returnValue?.step || 'retry';
|
|
714
|
+
const nextStepDecision = {
|
|
715
|
+
decision: shouldTerminate ? 'success' : 'retry',
|
|
716
|
+
reasoning: shouldTerminate ? 'Sub-agent execution completed, terminating as requested' : 'Sub-agent completed, continuing execution',
|
|
717
|
+
nextStepDetails: { type: nextStepType, returnValue: subAgentResult.returnValue }
|
|
718
|
+
};
|
|
719
|
+
this._executionChain.push({
|
|
720
|
+
stepEntity,
|
|
721
|
+
executionType: 'sub-agent',
|
|
722
|
+
executionResult,
|
|
723
|
+
nextStepDecision,
|
|
724
|
+
startTime,
|
|
725
|
+
endTime: new Date(),
|
|
726
|
+
durationMs: new Date().getTime() - startTime.getTime()
|
|
727
|
+
});
|
|
728
|
+
const outputData = {
|
|
729
|
+
subAgentResult: {
|
|
730
|
+
success: subAgentResult.success,
|
|
731
|
+
finalStep: subAgentResult.finalStep,
|
|
732
|
+
returnValue: subAgentResult.returnValue,
|
|
733
|
+
errorMessage: subAgentResult.errorMessage,
|
|
734
|
+
agentRunId: subAgentResult.agentRun?.ID,
|
|
735
|
+
stepCount: this.countStepsInTree(subAgentResult.executionTree)
|
|
736
|
+
},
|
|
737
|
+
shouldTerminate: shouldTerminate,
|
|
738
|
+
nextStep: nextStepDecision.decision
|
|
739
|
+
};
|
|
740
|
+
await this.finalizeStepEntity(stepEntity, subAgentResult.success, subAgentResult.errorMessage, outputData);
|
|
741
|
+
const subAgentSummary = {
|
|
742
|
+
subAgentName: subAgentRequest.name,
|
|
743
|
+
subAgentId: subAgentRequest.id,
|
|
744
|
+
success: subAgentResult.success,
|
|
745
|
+
finalStep: subAgentResult.finalStep,
|
|
746
|
+
returnValue: subAgentResult.returnValue,
|
|
747
|
+
errorMessage: subAgentResult.errorMessage || null
|
|
748
|
+
};
|
|
749
|
+
const resultMessage = subAgentResult.success
|
|
750
|
+
? `Sub-agent completed successfully:\n${JSON.stringify(subAgentSummary, null, 2)}`
|
|
751
|
+
: `Sub-agent failed:\n${JSON.stringify(subAgentSummary, null, 2)}`;
|
|
752
|
+
params.conversationMessages.push({
|
|
753
|
+
role: 'user',
|
|
754
|
+
content: resultMessage
|
|
755
|
+
});
|
|
756
|
+
if (shouldTerminate) {
|
|
757
|
+
return { terminate: true, returnValue: subAgentResult.returnValue };
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
return {
|
|
761
|
+
terminate: false,
|
|
762
|
+
nextStep: {
|
|
763
|
+
step: 'retry',
|
|
764
|
+
retryReason: `Analyzing results from "${subAgentRequest.name}" agent to integrate findings`
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
catch (error) {
|
|
770
|
+
await this.finalizeStepEntity(stepEntity, false, error.message);
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
async executeActionsStep(params, actions) {
|
|
775
|
+
if (params.cancellationToken?.aborted) {
|
|
776
|
+
throw new Error('Cancelled before action execution');
|
|
777
|
+
}
|
|
778
|
+
let progressMessage;
|
|
779
|
+
if (actions.length === 1) {
|
|
780
|
+
const action = actions[0];
|
|
781
|
+
progressMessage = `Executing action: **${action.name}**`;
|
|
782
|
+
if (action.params && Object.keys(action.params).length > 0) {
|
|
783
|
+
const paramsList = Object.entries(action.params)
|
|
784
|
+
.map(([key, value]) => {
|
|
785
|
+
const displayValue = typeof value === 'object'
|
|
786
|
+
? JSON.stringify(value, null, 2)
|
|
787
|
+
: String(value);
|
|
788
|
+
return ` - \`${key}\`: ${displayValue}`;
|
|
789
|
+
})
|
|
790
|
+
.join('\n');
|
|
791
|
+
progressMessage += `\n${paramsList}`;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
progressMessage = `Executing ${actions.length} actions:`;
|
|
796
|
+
actions.forEach(action => {
|
|
797
|
+
progressMessage += `\n\n• **${action.name}**`;
|
|
798
|
+
if (action.params && Object.keys(action.params).length > 0) {
|
|
799
|
+
const paramsList = Object.entries(action.params)
|
|
800
|
+
.map(([key, value]) => {
|
|
801
|
+
const displayValue = typeof value === 'object'
|
|
802
|
+
? JSON.stringify(value, null, 2)
|
|
803
|
+
: String(value);
|
|
804
|
+
return ` - \`${key}\`: ${displayValue}`;
|
|
805
|
+
})
|
|
806
|
+
.join('\n');
|
|
807
|
+
progressMessage += `\n${paramsList}`;
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
params.onProgress?.({
|
|
812
|
+
step: 'action_execution',
|
|
813
|
+
percentage: 50,
|
|
814
|
+
message: this.formatHierarchicalMessage(progressMessage),
|
|
815
|
+
metadata: {
|
|
816
|
+
actionCount: actions.length,
|
|
817
|
+
actionNames: actions.map(a => a.name)
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
const actionMessage = actions.length === 1
|
|
821
|
+
? `I'm executing the "${actions[0].name}" action...`
|
|
822
|
+
: `I'm executing ${actions.length} actions to gather the information needed:\n${actions.map(a => `• ${a.name}`).join('\n')}`;
|
|
823
|
+
params.conversationMessages.push({
|
|
824
|
+
role: 'assistant',
|
|
825
|
+
content: actionMessage
|
|
826
|
+
});
|
|
827
|
+
const actionSteps = [];
|
|
828
|
+
for (const action of actions) {
|
|
829
|
+
const startTime = new Date();
|
|
830
|
+
const stepEntity = await this.createStepEntity('action', `Execute Action: ${action.name}`, params.contextUser, action.id);
|
|
831
|
+
actionSteps.push({ action, stepEntity, startTime });
|
|
832
|
+
}
|
|
833
|
+
const actionPromises = actionSteps.map(async ({ action, stepEntity, startTime }) => {
|
|
834
|
+
try {
|
|
835
|
+
const actionResults = await this.ExecuteActions([action], params.contextUser);
|
|
836
|
+
const actionResult = actionResults[0];
|
|
837
|
+
const executionResult = {
|
|
838
|
+
type: 'action',
|
|
839
|
+
actionId: action.id,
|
|
840
|
+
actionName: action.name,
|
|
841
|
+
result: actionResult
|
|
842
|
+
};
|
|
843
|
+
const nextStepDecision = {
|
|
844
|
+
decision: 'retry',
|
|
845
|
+
reasoning: 'Action completed successfully',
|
|
846
|
+
nextStepDetails: undefined
|
|
847
|
+
};
|
|
848
|
+
this._executionChain.push({
|
|
849
|
+
stepEntity,
|
|
850
|
+
executionType: 'action',
|
|
851
|
+
executionResult,
|
|
852
|
+
nextStepDecision,
|
|
853
|
+
startTime,
|
|
854
|
+
endTime: new Date(),
|
|
855
|
+
durationMs: new Date().getTime() - startTime.getTime()
|
|
856
|
+
});
|
|
857
|
+
const outputData = {
|
|
858
|
+
actionResult: {
|
|
859
|
+
success: actionResult.Success,
|
|
860
|
+
resultCode: actionResult.ResultCode,
|
|
861
|
+
message: actionResult.Message,
|
|
862
|
+
result: actionResult.ResultType === 'ComplexObject'
|
|
863
|
+
? actionResult.Complex
|
|
864
|
+
: actionResult.Simple
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
await this.finalizeStepEntity(stepEntity, actionResult.Success, actionResult.Success ? undefined : actionResult.Message, outputData);
|
|
868
|
+
return { success: true, result: actionResult };
|
|
869
|
+
}
|
|
870
|
+
catch (error) {
|
|
871
|
+
await this.finalizeStepEntity(stepEntity, false, error.message);
|
|
872
|
+
return { success: false, error: error.message };
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
const actionResults = await Promise.all(actionPromises);
|
|
876
|
+
if (params.cancellationToken?.aborted) {
|
|
877
|
+
throw new Error('Cancelled after action execution');
|
|
878
|
+
}
|
|
879
|
+
const actionSummaries = actionSteps.map((step, index) => {
|
|
880
|
+
const result = actionResults[index];
|
|
881
|
+
const actionResult = result.success ? result.result : null;
|
|
882
|
+
return {
|
|
883
|
+
actionName: step.action.name,
|
|
884
|
+
actionId: step.action.id,
|
|
885
|
+
params: step.action.params,
|
|
886
|
+
success: result.success,
|
|
887
|
+
resultCode: actionResult?.ResultCode || (result.success ? 'SUCCESS' : 'ERROR'),
|
|
888
|
+
message: result.success ? actionResult?.Message || 'Action completed' : result.error
|
|
889
|
+
};
|
|
890
|
+
});
|
|
891
|
+
const failedActions = actionSummaries.filter(a => !a.success);
|
|
892
|
+
const resultsMessage = failedActions.length > 0
|
|
893
|
+
? `Action results (${failedActions.length} failed):\n${JSON.stringify(actionSummaries, null, 2)}`
|
|
894
|
+
: `Action results (all succeeded):\n${JSON.stringify(actionSummaries, null, 2)}`;
|
|
895
|
+
params.conversationMessages.push({
|
|
896
|
+
role: 'user',
|
|
897
|
+
content: resultsMessage
|
|
898
|
+
});
|
|
899
|
+
return {
|
|
900
|
+
terminate: false,
|
|
901
|
+
nextStep: {
|
|
902
|
+
step: 'retry',
|
|
903
|
+
retryReason: failedActions.length > 0
|
|
904
|
+
? `Processing results with ${failedActions.length} failed action(s): ${failedActions.map(a => a.actionName).join(', ')}`
|
|
905
|
+
: `Analyzing results from ${actionSummaries.length} completed action(s) to formulate response`
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
async executeChatStep(params, userMessage) {
|
|
910
|
+
const startTime = new Date();
|
|
911
|
+
const stepEntity = await this.createStepEntity('chat', 'User Interaction', params.contextUser);
|
|
912
|
+
const executionResult = {
|
|
913
|
+
type: 'chat',
|
|
914
|
+
userMessage,
|
|
915
|
+
result: { success: false, continueExecution: false }
|
|
916
|
+
};
|
|
917
|
+
const nextStepDecision = {
|
|
918
|
+
decision: 'failed',
|
|
919
|
+
reasoning: 'Chat functionality not implemented in base agent'
|
|
920
|
+
};
|
|
921
|
+
this._executionChain.push({
|
|
922
|
+
stepEntity,
|
|
923
|
+
executionType: 'chat',
|
|
924
|
+
executionResult,
|
|
925
|
+
nextStepDecision,
|
|
926
|
+
startTime,
|
|
927
|
+
endTime: new Date(),
|
|
928
|
+
durationMs: new Date().getTime() - startTime.getTime()
|
|
929
|
+
});
|
|
930
|
+
await this.finalizeStepEntity(stepEntity, false, 'Chat not implemented');
|
|
931
|
+
return { terminate: true };
|
|
932
|
+
}
|
|
933
|
+
async createFailureResult(errorMessage, contextUser) {
|
|
934
|
+
if (this._agentRun) {
|
|
935
|
+
this._agentRun.Status = 'Failed';
|
|
936
|
+
this._agentRun.CompletedAt = new Date();
|
|
937
|
+
this._agentRun.Success = false;
|
|
938
|
+
this._agentRun.ErrorMessage = errorMessage;
|
|
939
|
+
await this._agentRun.Save();
|
|
940
|
+
}
|
|
941
|
+
return {
|
|
942
|
+
success: false,
|
|
943
|
+
finalStep: 'failed',
|
|
944
|
+
errorMessage,
|
|
945
|
+
agentRun: this._agentRun,
|
|
946
|
+
executionTree: this.buildExecutionTree()
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
async createCancelledResult(message, contextUser) {
|
|
950
|
+
if (this._agentRun) {
|
|
951
|
+
this._agentRun.Status = 'Cancelled';
|
|
952
|
+
this._agentRun.CompletedAt = new Date();
|
|
953
|
+
this._agentRun.Success = false;
|
|
954
|
+
this._agentRun.ErrorMessage = message;
|
|
955
|
+
await this._agentRun.Save();
|
|
956
|
+
}
|
|
957
|
+
return {
|
|
958
|
+
success: false,
|
|
959
|
+
finalStep: 'failed',
|
|
960
|
+
errorMessage: message,
|
|
961
|
+
cancelled: true,
|
|
962
|
+
cancellationReason: 'user_requested',
|
|
963
|
+
agentRun: this._agentRun,
|
|
964
|
+
executionTree: this.buildExecutionTree()
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
async finalizeAgentRun(finalStep, returnValue, contextUser) {
|
|
968
|
+
if (this._agentRun) {
|
|
969
|
+
this._agentRun.Status = 'Completed';
|
|
970
|
+
this._agentRun.CompletedAt = new Date();
|
|
971
|
+
this._agentRun.Success = finalStep === 'success';
|
|
972
|
+
this._agentRun.Result = returnValue ? JSON.stringify(returnValue) : null;
|
|
973
|
+
await this._agentRun.Save();
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
success: finalStep === 'success' || finalStep === 'chat',
|
|
977
|
+
finalStep,
|
|
978
|
+
returnValue,
|
|
979
|
+
agentRun: this._agentRun,
|
|
980
|
+
executionTree: this.buildExecutionTree()
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
countStepsInTree(nodes) {
|
|
984
|
+
let count = 0;
|
|
985
|
+
for (const node of nodes) {
|
|
986
|
+
count++;
|
|
987
|
+
if (node.children && node.children.length > 0) {
|
|
988
|
+
count += this.countStepsInTree(node.children);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return count;
|
|
992
|
+
}
|
|
993
|
+
buildExecutionTree() {
|
|
994
|
+
const executionTree = [];
|
|
995
|
+
const allEvents = [];
|
|
996
|
+
let maxProgressStepNumber = 0;
|
|
997
|
+
for (const progressStep of this._allProgressSteps) {
|
|
998
|
+
allEvents.push({
|
|
999
|
+
type: 'progress',
|
|
1000
|
+
timestamp: progressStep.timestamp,
|
|
1001
|
+
data: progressStep
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
for (const chainStep of this._executionChain) {
|
|
1005
|
+
allEvents.push({
|
|
1006
|
+
type: 'execution',
|
|
1007
|
+
timestamp: chainStep.startTime,
|
|
1008
|
+
data: chainStep
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
allEvents.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
1012
|
+
for (const event of allEvents) {
|
|
1013
|
+
if (event.type === 'progress') {
|
|
1014
|
+
const progressData = event.data;
|
|
1015
|
+
maxProgressStepNumber++;
|
|
1016
|
+
const progressNode = {
|
|
1017
|
+
step: {
|
|
1018
|
+
ID: `progress-${event.timestamp.getTime()}`,
|
|
1019
|
+
StepNumber: maxProgressStepNumber,
|
|
1020
|
+
StepName: progressData.message,
|
|
1021
|
+
StepType: progressData.step || 'progress',
|
|
1022
|
+
Status: 'Completed',
|
|
1023
|
+
StartedAt: event.timestamp,
|
|
1024
|
+
CompletedAt: event.timestamp
|
|
1025
|
+
},
|
|
1026
|
+
inputData: null,
|
|
1027
|
+
outputData: {
|
|
1028
|
+
percentage: progressData.percentage,
|
|
1029
|
+
metadata: progressData.metadata
|
|
1030
|
+
},
|
|
1031
|
+
executionType: progressData.step || 'progress',
|
|
1032
|
+
startTime: event.timestamp,
|
|
1033
|
+
endTime: event.timestamp,
|
|
1034
|
+
durationMs: 0,
|
|
1035
|
+
children: [],
|
|
1036
|
+
depth: progressData.depth || this._runContext?.depth || 0,
|
|
1037
|
+
parentStepId: null,
|
|
1038
|
+
agentHierarchy: progressData.agentHierarchy || this._runContext?.agentHierarchy || []
|
|
1039
|
+
};
|
|
1040
|
+
executionTree.push(progressNode);
|
|
1041
|
+
}
|
|
1042
|
+
else {
|
|
1043
|
+
const chainStep = event.data;
|
|
1044
|
+
const stepEntity = chainStep.stepEntity;
|
|
1045
|
+
let inputData = null;
|
|
1046
|
+
let outputData = null;
|
|
1047
|
+
try {
|
|
1048
|
+
if (stepEntity.InputData) {
|
|
1049
|
+
inputData = JSON.parse(stepEntity.InputData);
|
|
1050
|
+
}
|
|
1051
|
+
if (stepEntity.OutputData) {
|
|
1052
|
+
outputData = JSON.parse(stepEntity.OutputData);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
catch (e) {
|
|
1056
|
+
inputData = stepEntity.InputData;
|
|
1057
|
+
outputData = stepEntity.OutputData;
|
|
1058
|
+
}
|
|
1059
|
+
const node = {
|
|
1060
|
+
step: stepEntity,
|
|
1061
|
+
inputData,
|
|
1062
|
+
outputData,
|
|
1063
|
+
executionType: chainStep.executionType,
|
|
1064
|
+
startTime: chainStep.startTime,
|
|
1065
|
+
endTime: chainStep.endTime,
|
|
1066
|
+
durationMs: chainStep.durationMs,
|
|
1067
|
+
nextStepDecision: chainStep.nextStepDecision,
|
|
1068
|
+
children: [],
|
|
1069
|
+
depth: this._runContext?.depth || 0,
|
|
1070
|
+
parentStepId: null,
|
|
1071
|
+
agentHierarchy: this._runContext?.agentHierarchy || []
|
|
1072
|
+
};
|
|
1073
|
+
if (chainStep.executionType === 'sub-agent' && chainStep.executionResult?.type === 'sub-agent') {
|
|
1074
|
+
const subAgentResult = chainStep.executionResult.result;
|
|
1075
|
+
if (subAgentResult.executionTree) {
|
|
1076
|
+
node.children = subAgentResult.executionTree.map(childNode => ({
|
|
1077
|
+
...childNode,
|
|
1078
|
+
parentStepId: stepEntity.ID,
|
|
1079
|
+
depth: (this._runContext?.depth || 0) + 1
|
|
1080
|
+
}));
|
|
1081
|
+
this.sortExecutionTreeByStepNumber(node.children);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
executionTree.push(node);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
this.sortExecutionTreeByStepNumber(executionTree);
|
|
1088
|
+
return executionTree;
|
|
1089
|
+
}
|
|
1090
|
+
sortExecutionTreeByStepNumber(nodes) {
|
|
1091
|
+
nodes.sort((a, b) => {
|
|
1092
|
+
const aStepNumber = a.step?.StepNumber || 0;
|
|
1093
|
+
const bStepNumber = b.step?.StepNumber || 0;
|
|
1094
|
+
return aStepNumber - bStepNumber;
|
|
1095
|
+
});
|
|
1096
|
+
for (const node of nodes) {
|
|
1097
|
+
if (node.children && node.children.length > 0) {
|
|
1098
|
+
this.sortExecutionTreeByStepNumber(node.children);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
getNextStepReasoning(nextStep) {
|
|
1103
|
+
switch (nextStep.step) {
|
|
1104
|
+
case 'success':
|
|
1105
|
+
return 'Agent completed successfully';
|
|
1106
|
+
case 'failed':
|
|
1107
|
+
return `Agent failed: ${nextStep.errorMessage || 'Unknown error'}`;
|
|
1108
|
+
case 'retry':
|
|
1109
|
+
return nextStep.retryReason || 'Retrying with additional context';
|
|
1110
|
+
case 'sub-agent':
|
|
1111
|
+
return `Invoking sub-agent: ${nextStep.subAgent?.name}`;
|
|
1112
|
+
case 'actions':
|
|
1113
|
+
return `Executing ${nextStep.actions?.length || 0} action(s)`;
|
|
1114
|
+
case 'chat':
|
|
1115
|
+
return 'User interaction required';
|
|
1116
|
+
default:
|
|
1117
|
+
return 'Unknown next step';
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
getNextStepDetails(nextStep) {
|
|
1121
|
+
switch (nextStep.step) {
|
|
1122
|
+
case 'success':
|
|
1123
|
+
case 'failed':
|
|
1124
|
+
return { type: 'complete', returnValue: nextStep.returnValue };
|
|
1125
|
+
case 'retry':
|
|
1126
|
+
return {
|
|
1127
|
+
type: 'retry',
|
|
1128
|
+
retryReason: nextStep.retryReason || '',
|
|
1129
|
+
retryInstructions: nextStep.retryInstructions || ''
|
|
1130
|
+
};
|
|
1131
|
+
case 'sub-agent':
|
|
1132
|
+
return nextStep.subAgent ? { type: 'sub-agent', subAgent: nextStep.subAgent } : undefined;
|
|
1133
|
+
case 'actions':
|
|
1134
|
+
return nextStep.actions ? { type: 'action', actions: nextStep.actions } : undefined;
|
|
1135
|
+
case 'chat':
|
|
1136
|
+
return { type: 'chat', message: nextStep.userMessage || '' };
|
|
1137
|
+
default:
|
|
1138
|
+
return undefined;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
154
1141
|
}
|
|
155
1142
|
exports.BaseAgent = BaseAgent;
|
|
156
1143
|
//# sourceMappingURL=base-agent.js.map
|