@memberjunction/ai-prompts 2.44.0 → 2.45.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 +937 -9
- package/dist/AIPromptCategoryExtended.d.ts +1 -1
- package/dist/AIPromptCategoryExtended.d.ts.map +1 -1
- package/dist/AIPromptCategoryExtended.js +1 -1
- package/dist/AIPromptCategoryExtended.js.map +1 -1
- package/dist/AIPromptRunner.d.ts +83 -5
- package/dist/AIPromptRunner.d.ts.map +1 -1
- package/dist/AIPromptRunner.js +561 -60
- package/dist/AIPromptRunner.js.map +1 -1
- package/dist/ExecutionPlanner.d.ts +6 -4
- package/dist/ExecutionPlanner.d.ts.map +1 -1
- package/dist/ExecutionPlanner.js +39 -36
- package/dist/ExecutionPlanner.js.map +1 -1
- package/dist/ParallelExecution.d.ts +96 -6
- package/dist/ParallelExecution.d.ts.map +1 -1
- package/dist/ParallelExecutionCoordinator.d.ts +22 -3
- package/dist/ParallelExecutionCoordinator.d.ts.map +1 -1
- package/dist/ParallelExecutionCoordinator.js +490 -37
- package/dist/ParallelExecutionCoordinator.js.map +1 -1
- package/package.json +8 -7
|
@@ -1,29 +1,151 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
exports.ParallelExecutionCoordinator = void 0;
|
|
4
27
|
const core_1 = require("@memberjunction/core");
|
|
5
28
|
const global_1 = require("@memberjunction/global");
|
|
6
29
|
const ai_1 = require("@memberjunction/ai");
|
|
30
|
+
const aiengine_1 = require("@memberjunction/aiengine");
|
|
31
|
+
class ParallelProgressTracker {
|
|
32
|
+
constructor(totalTasks, totalGroups, progressCallbacks) {
|
|
33
|
+
this.completedTasks = 0;
|
|
34
|
+
this.successfulTasks = 0;
|
|
35
|
+
this.failedTasks = 0;
|
|
36
|
+
this.cancelledTasks = 0;
|
|
37
|
+
this.currentGroup = 0;
|
|
38
|
+
this.activeTasks = [];
|
|
39
|
+
this.totalTokenUsage = {};
|
|
40
|
+
this.totalTasks = totalTasks;
|
|
41
|
+
this.totalGroups = totalGroups;
|
|
42
|
+
this.startTime = new Date();
|
|
43
|
+
this.progressCallbacks = progressCallbacks;
|
|
44
|
+
}
|
|
45
|
+
updateProgress(currentGroup) {
|
|
46
|
+
this.currentGroup = currentGroup;
|
|
47
|
+
this.sendProgressUpdate();
|
|
48
|
+
}
|
|
49
|
+
addActiveTask(taskId) {
|
|
50
|
+
if (!this.activeTasks.includes(taskId)) {
|
|
51
|
+
this.activeTasks.push(taskId);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
removeActiveTask(taskId) {
|
|
55
|
+
const index = this.activeTasks.indexOf(taskId);
|
|
56
|
+
if (index > -1) {
|
|
57
|
+
this.activeTasks.splice(index, 1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
taskCompleted(result) {
|
|
61
|
+
this.completedTasks++;
|
|
62
|
+
this.removeActiveTask(result.task.taskId);
|
|
63
|
+
if (result.success) {
|
|
64
|
+
this.successfulTasks++;
|
|
65
|
+
if (result.tokensUsed) {
|
|
66
|
+
this.totalTokenUsage.totalTokens = (this.totalTokenUsage.totalTokens || 0) + result.tokensUsed;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else if (result.cancelled) {
|
|
70
|
+
this.cancelledTasks++;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this.failedTasks++;
|
|
74
|
+
}
|
|
75
|
+
if (this.progressCallbacks?.getStreamingConfig()?.enabled) {
|
|
76
|
+
const config = this.progressCallbacks.getStreamingConfig();
|
|
77
|
+
if (config.callbacks?.OnTaskComplete) {
|
|
78
|
+
config.callbacks.OnTaskComplete(result, this.getCurrentProgress());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
this.sendProgressUpdate();
|
|
82
|
+
}
|
|
83
|
+
getCurrentProgress() {
|
|
84
|
+
return {
|
|
85
|
+
completedTasks: this.completedTasks,
|
|
86
|
+
totalTasks: this.totalTasks,
|
|
87
|
+
successfulTasks: this.successfulTasks,
|
|
88
|
+
failedTasks: this.failedTasks,
|
|
89
|
+
cancelledTasks: this.cancelledTasks,
|
|
90
|
+
currentGroup: this.currentGroup,
|
|
91
|
+
totalGroups: this.totalGroups,
|
|
92
|
+
totalTokenUsage: this.totalTokenUsage,
|
|
93
|
+
totalElapsedTimeMS: new Date().getTime() - this.startTime.getTime(),
|
|
94
|
+
activeTasks: [...this.activeTasks],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
sendProgressUpdate() {
|
|
98
|
+
if (this.progressCallbacks?.getStreamingConfig()?.enabled) {
|
|
99
|
+
const config = this.progressCallbacks.getStreamingConfig();
|
|
100
|
+
if (config.callbacks?.OnParallelProgress) {
|
|
101
|
+
config.callbacks.OnParallelProgress(this.getCurrentProgress());
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
7
106
|
class ParallelExecutionCoordinator {
|
|
8
107
|
constructor() {
|
|
108
|
+
this._metadata = new core_1.Metadata();
|
|
9
109
|
this._defaultConfig = {
|
|
10
110
|
maxConcurrentExecutions: 5,
|
|
11
111
|
taskTimeoutMS: 30000,
|
|
12
112
|
failFast: false,
|
|
13
113
|
collectPartialResults: true,
|
|
14
114
|
maxRetries: 3,
|
|
15
|
-
retryDelayMS: 1000
|
|
115
|
+
retryDelayMS: 1000,
|
|
16
116
|
};
|
|
17
117
|
}
|
|
18
|
-
async executeTasksInParallel(tasks, config) {
|
|
118
|
+
async executeTasksInParallel(tasks, config, parentPromptRunId, cancellationToken, progressCallbacks) {
|
|
19
119
|
const startTime = new Date();
|
|
20
120
|
const executionConfig = { ...this._defaultConfig, ...config };
|
|
121
|
+
if (cancellationToken?.aborted) {
|
|
122
|
+
(0, core_1.LogStatus)('Parallel execution cancelled before starting');
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
taskResults: [],
|
|
126
|
+
groupResults: new Map(),
|
|
127
|
+
totalExecutionTimeMS: 0,
|
|
128
|
+
successCount: 0,
|
|
129
|
+
failureCount: 0,
|
|
130
|
+
cancelledCount: tasks.length,
|
|
131
|
+
totalTokensUsed: 0,
|
|
132
|
+
errors: ['Execution was cancelled before starting'],
|
|
133
|
+
startTime,
|
|
134
|
+
endTime: new Date(),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
21
137
|
(0, core_1.LogStatus)(`Starting parallel execution of ${tasks.length} tasks with config: ${JSON.stringify(executionConfig)}`);
|
|
22
138
|
try {
|
|
139
|
+
if (cancellationToken) {
|
|
140
|
+
tasks.forEach((task) => {
|
|
141
|
+
task.cancellationToken = cancellationToken;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
23
144
|
const executionGroups = this.groupTasksByExecutionGroup(tasks);
|
|
24
|
-
const
|
|
145
|
+
const progressTracker = new ParallelProgressTracker(tasks.length, executionGroups.length, progressCallbacks);
|
|
146
|
+
const allResults = await this.executeGroupsSequentially(executionGroups, executionConfig, parentPromptRunId, cancellationToken, progressTracker);
|
|
25
147
|
const result = this.aggregateResults(allResults, startTime, new Date());
|
|
26
|
-
(0, core_1.LogStatus)(`Parallel execution completed: ${result.successCount}/${tasks.length} tasks successful`);
|
|
148
|
+
(0, core_1.LogStatus)(`Parallel execution completed: ${result.successCount}/${tasks.length} tasks successful, ${result.failureCount} failed, ${result.cancelledCount} cancelled`);
|
|
27
149
|
return result;
|
|
28
150
|
}
|
|
29
151
|
catch (error) {
|
|
@@ -35,14 +157,15 @@ class ParallelExecutionCoordinator {
|
|
|
35
157
|
totalExecutionTimeMS: new Date().getTime() - startTime.getTime(),
|
|
36
158
|
successCount: 0,
|
|
37
159
|
failureCount: tasks.length,
|
|
160
|
+
cancelledCount: 0,
|
|
38
161
|
totalTokensUsed: 0,
|
|
39
162
|
errors: [error.message],
|
|
40
163
|
startTime,
|
|
41
|
-
endTime: new Date()
|
|
164
|
+
endTime: new Date(),
|
|
42
165
|
};
|
|
43
166
|
}
|
|
44
167
|
}
|
|
45
|
-
async selectBestResult(results, config) {
|
|
168
|
+
async selectBestResult(results, config, parentPromptRunId, cancellationToken) {
|
|
46
169
|
if (results.length === 0) {
|
|
47
170
|
return null;
|
|
48
171
|
}
|
|
@@ -56,7 +179,7 @@ class ParallelExecutionCoordinator {
|
|
|
56
179
|
case 'Random':
|
|
57
180
|
return this.selectRandomResult(results);
|
|
58
181
|
case 'PromptSelector':
|
|
59
|
-
return await this.selectResultWithPrompt(results, config.selectorPromptId);
|
|
182
|
+
return await this.selectResultWithPrompt(results, config.selectorPromptId, parentPromptRunId, cancellationToken);
|
|
60
183
|
case 'Consensus':
|
|
61
184
|
return this.selectConsensusResult(results);
|
|
62
185
|
default:
|
|
@@ -78,60 +201,109 @@ class ParallelExecutionCoordinator {
|
|
|
78
201
|
groupTasks.sort((a, b) => b.priority - a.priority);
|
|
79
202
|
groups.push({
|
|
80
203
|
groupNumber,
|
|
81
|
-
tasks: groupTasks
|
|
204
|
+
tasks: groupTasks,
|
|
82
205
|
});
|
|
83
206
|
}
|
|
84
207
|
groups.sort((a, b) => a.groupNumber - b.groupNumber);
|
|
85
208
|
(0, core_1.LogStatus)(`Grouped ${tasks.length} tasks into ${groups.length} execution groups`);
|
|
86
209
|
return groups;
|
|
87
210
|
}
|
|
88
|
-
async executeGroupsSequentially(groups, config) {
|
|
211
|
+
async executeGroupsSequentially(groups, config, parentPromptRunId, cancellationToken, progressTracker) {
|
|
89
212
|
const allResults = [];
|
|
90
213
|
for (const group of groups) {
|
|
214
|
+
if (cancellationToken?.aborted) {
|
|
215
|
+
(0, core_1.LogStatus)(`Group execution cancelled at group ${group.groupNumber}`);
|
|
216
|
+
const cancelledResults = group.tasks.map((task) => ({
|
|
217
|
+
task,
|
|
218
|
+
success: false,
|
|
219
|
+
cancelled: true,
|
|
220
|
+
errorMessage: 'Task cancelled',
|
|
221
|
+
executionTimeMS: 0,
|
|
222
|
+
startTime: new Date(),
|
|
223
|
+
endTime: new Date(),
|
|
224
|
+
}));
|
|
225
|
+
allResults.push(...cancelledResults);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
91
228
|
(0, core_1.LogStatus)(`Executing group ${group.groupNumber} with ${group.tasks.length} tasks`);
|
|
92
|
-
|
|
229
|
+
progressTracker?.updateProgress(group.groupNumber);
|
|
230
|
+
const groupResults = await this.executeGroupInParallel(group, config, parentPromptRunId, cancellationToken, progressTracker);
|
|
93
231
|
allResults.push(...groupResults);
|
|
94
|
-
if (config.failFast && groupResults.some(r => !r.success)) {
|
|
95
|
-
const failedTasks = groupResults.filter(r => !r.success);
|
|
232
|
+
if (config.failFast && groupResults.some((r) => !r.success)) {
|
|
233
|
+
const failedTasks = groupResults.filter((r) => !r.success);
|
|
96
234
|
(0, core_1.LogError)(`Failing fast due to ${failedTasks.length} failed tasks in group ${group.groupNumber}`);
|
|
97
235
|
break;
|
|
98
236
|
}
|
|
99
237
|
}
|
|
100
238
|
return allResults;
|
|
101
239
|
}
|
|
102
|
-
async executeGroupInParallel(group, config) {
|
|
240
|
+
async executeGroupInParallel(group, config, parentPromptRunId, cancellationToken, progressTracker) {
|
|
103
241
|
const maxConcurrent = Math.min(config.maxConcurrentExecutions, group.tasks.length);
|
|
104
242
|
const results = [];
|
|
105
243
|
const executing = [];
|
|
106
244
|
let taskIndex = 0;
|
|
245
|
+
let executionOrder = 0;
|
|
107
246
|
while (taskIndex < group.tasks.length || executing.length > 0) {
|
|
247
|
+
if (cancellationToken?.aborted) {
|
|
248
|
+
(0, core_1.LogStatus)(`Task execution cancelled in group ${group.groupNumber}`);
|
|
249
|
+
while (taskIndex < group.tasks.length) {
|
|
250
|
+
const task = group.tasks[taskIndex++];
|
|
251
|
+
results.push({
|
|
252
|
+
task,
|
|
253
|
+
success: false,
|
|
254
|
+
cancelled: true,
|
|
255
|
+
errorMessage: 'Task cancelled',
|
|
256
|
+
executionTimeMS: 0,
|
|
257
|
+
startTime: new Date(),
|
|
258
|
+
endTime: new Date(),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
108
263
|
while (executing.length < maxConcurrent && taskIndex < group.tasks.length) {
|
|
109
264
|
const task = group.tasks[taskIndex++];
|
|
110
|
-
|
|
265
|
+
progressTracker?.addActiveTask(task.taskId);
|
|
266
|
+
const execution = this.executeTask(task, config, parentPromptRunId, executionOrder++);
|
|
111
267
|
executing.push(execution);
|
|
112
268
|
}
|
|
113
269
|
if (executing.length > 0) {
|
|
114
270
|
const result = await Promise.race(executing);
|
|
115
271
|
results.push(result);
|
|
116
|
-
|
|
272
|
+
progressTracker?.taskCompleted(result);
|
|
273
|
+
const completedIndex = executing.findIndex((p) => p === Promise.resolve(result));
|
|
117
274
|
if (completedIndex !== -1) {
|
|
118
275
|
executing.splice(completedIndex, 1);
|
|
119
276
|
}
|
|
120
277
|
}
|
|
121
278
|
}
|
|
122
|
-
|
|
279
|
+
const successfulResults = results.filter((r) => r.success);
|
|
280
|
+
const cancelledResults = results.filter((r) => r.cancelled);
|
|
281
|
+
(0, core_1.LogStatus)(`Group ${group.groupNumber} completed: ${successfulResults.length}/${results.length} successful, ${cancelledResults.length} cancelled`);
|
|
123
282
|
return results;
|
|
124
283
|
}
|
|
125
|
-
async executeTask(task, config) {
|
|
284
|
+
async executeTask(task, config, parentPromptRunId, executionOrder) {
|
|
126
285
|
const startTime = new Date();
|
|
127
286
|
let lastError = null;
|
|
128
287
|
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
129
288
|
try {
|
|
289
|
+
if (task.cancellationToken?.aborted) {
|
|
290
|
+
const endTime = new Date();
|
|
291
|
+
(0, core_1.LogStatus)(`Task ${task.taskId} cancelled before attempt ${attempt + 1}`);
|
|
292
|
+
return {
|
|
293
|
+
task,
|
|
294
|
+
success: false,
|
|
295
|
+
cancelled: true,
|
|
296
|
+
errorMessage: 'Task cancelled',
|
|
297
|
+
executionTimeMS: endTime.getTime() - startTime.getTime(),
|
|
298
|
+
startTime,
|
|
299
|
+
endTime,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
130
302
|
if (attempt > 0) {
|
|
131
303
|
await this.delay(config.retryDelayMS * attempt);
|
|
132
304
|
(0, core_1.LogStatus)(`Retrying task ${task.taskId}, attempt ${attempt + 1}/${config.maxRetries + 1}`);
|
|
133
305
|
}
|
|
134
|
-
const result = await this.executeSingleTask(task, config.taskTimeoutMS);
|
|
306
|
+
const result = await this.executeSingleTask(task, config.taskTimeoutMS, parentPromptRunId, executionOrder);
|
|
135
307
|
result.startTime = startTime;
|
|
136
308
|
result.endTime = new Date();
|
|
137
309
|
return result;
|
|
@@ -151,31 +323,53 @@ class ParallelExecutionCoordinator {
|
|
|
151
323
|
errorMessage: lastError?.message || 'Unknown error',
|
|
152
324
|
executionTimeMS: endTime.getTime() - startTime.getTime(),
|
|
153
325
|
startTime,
|
|
154
|
-
endTime
|
|
326
|
+
endTime,
|
|
155
327
|
};
|
|
156
328
|
}
|
|
157
|
-
async executeSingleTask(task, timeoutMS) {
|
|
329
|
+
async executeSingleTask(task, timeoutMS, parentPromptRunId, executionOrder) {
|
|
158
330
|
const startTime = new Date();
|
|
331
|
+
let childPromptRun = null;
|
|
159
332
|
try {
|
|
333
|
+
if (parentPromptRunId) {
|
|
334
|
+
childPromptRun = await this.createChildPromptRun(task, startTime, parentPromptRunId, executionOrder);
|
|
335
|
+
}
|
|
160
336
|
const apiKey = (0, ai_1.GetAIAPIKey)(task.model.DriverClass);
|
|
161
337
|
const llm = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(ai_1.BaseLLM, task.model.DriverClass, apiKey);
|
|
162
338
|
const params = new ai_1.ChatParams();
|
|
163
339
|
params.model = task.model.APIName;
|
|
164
|
-
params.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
340
|
+
params.cancellationToken = task.cancellationToken;
|
|
341
|
+
if (task.streamingConfig?.enabled && task.streamingConfig.callbacks?.OnContent) {
|
|
342
|
+
params.streaming = true;
|
|
343
|
+
params.streamingCallbacks = {
|
|
344
|
+
OnContent: task.streamingConfig.callbacks.OnContent,
|
|
345
|
+
OnComplete: task.streamingConfig.callbacks.OnComplete,
|
|
346
|
+
OnError: task.streamingConfig.callbacks.OnError,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
params.messages = this.buildMessageArray(task.renderedPrompt, task.conversationMessages, task.templateMessageRole || 'system');
|
|
170
350
|
if (task.modelParameters) {
|
|
171
351
|
Object.assign(params, task.modelParameters);
|
|
172
352
|
}
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
353
|
+
const racePromises = [llm.ChatCompletion(params)];
|
|
354
|
+
racePromises.push(new Promise((_, reject) => setTimeout(() => reject(new Error('Task execution timeout')), timeoutMS)));
|
|
355
|
+
if (task.cancellationToken) {
|
|
356
|
+
racePromises.push(new Promise((_, reject) => {
|
|
357
|
+
if (task.cancellationToken.aborted) {
|
|
358
|
+
reject(new Error('Task execution cancelled'));
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
task.cancellationToken.addEventListener('abort', () => {
|
|
362
|
+
reject(new Error('Task execution cancelled'));
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
const modelResult = (await Promise.race(racePromises));
|
|
177
368
|
const endTime = new Date();
|
|
178
369
|
const executionTimeMS = endTime.getTime() - startTime.getTime();
|
|
370
|
+
if (childPromptRun) {
|
|
371
|
+
await this.updateChildPromptRun(childPromptRun, modelResult, endTime, executionTimeMS);
|
|
372
|
+
}
|
|
179
373
|
return {
|
|
180
374
|
task,
|
|
181
375
|
success: modelResult.success,
|
|
@@ -184,11 +378,34 @@ class ParallelExecutionCoordinator {
|
|
|
184
378
|
tokensUsed: modelResult.data?.usage?.totalTokens,
|
|
185
379
|
modelResult,
|
|
186
380
|
startTime,
|
|
187
|
-
endTime
|
|
381
|
+
endTime,
|
|
382
|
+
promptRun: childPromptRun,
|
|
188
383
|
};
|
|
189
384
|
}
|
|
190
385
|
catch (error) {
|
|
191
386
|
const endTime = new Date();
|
|
387
|
+
const executionTimeMS = endTime.getTime() - startTime.getTime();
|
|
388
|
+
const isCancelled = error.message.includes('cancelled');
|
|
389
|
+
if (childPromptRun) {
|
|
390
|
+
childPromptRun.CompletedAt = endTime;
|
|
391
|
+
childPromptRun.ExecutionTimeMS = executionTimeMS;
|
|
392
|
+
childPromptRun.Success = false;
|
|
393
|
+
childPromptRun.ErrorMessage = error.message;
|
|
394
|
+
childPromptRun.Result = `ERROR: ${error.message}`;
|
|
395
|
+
await childPromptRun.Save();
|
|
396
|
+
}
|
|
397
|
+
if (isCancelled) {
|
|
398
|
+
return {
|
|
399
|
+
task,
|
|
400
|
+
success: false,
|
|
401
|
+
cancelled: true,
|
|
402
|
+
errorMessage: error.message,
|
|
403
|
+
executionTimeMS,
|
|
404
|
+
startTime,
|
|
405
|
+
endTime,
|
|
406
|
+
promptRun: childPromptRun,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
192
409
|
throw new Error(`Task execution failed: ${error.message}`);
|
|
193
410
|
}
|
|
194
411
|
}
|
|
@@ -197,6 +414,7 @@ class ParallelExecutionCoordinator {
|
|
|
197
414
|
const errors = [];
|
|
198
415
|
let totalTokensUsed = 0;
|
|
199
416
|
let successCount = 0;
|
|
417
|
+
let cancelledCount = 0;
|
|
200
418
|
for (const result of taskResults) {
|
|
201
419
|
const groupNumber = result.task.executionGroup;
|
|
202
420
|
if (!groupResults.has(groupNumber)) {
|
|
@@ -208,6 +426,9 @@ class ParallelExecutionCoordinator {
|
|
|
208
426
|
totalTokensUsed += result.tokensUsed || 0;
|
|
209
427
|
}
|
|
210
428
|
else {
|
|
429
|
+
if (result.cancelled) {
|
|
430
|
+
cancelledCount++;
|
|
431
|
+
}
|
|
211
432
|
if (result.errorMessage) {
|
|
212
433
|
errors.push(result.errorMessage);
|
|
213
434
|
}
|
|
@@ -219,11 +440,12 @@ class ParallelExecutionCoordinator {
|
|
|
219
440
|
groupResults,
|
|
220
441
|
totalExecutionTimeMS: endTime.getTime() - startTime.getTime(),
|
|
221
442
|
successCount,
|
|
222
|
-
failureCount: taskResults.length - successCount,
|
|
443
|
+
failureCount: taskResults.length - successCount - cancelledCount,
|
|
444
|
+
cancelledCount,
|
|
223
445
|
totalTokensUsed,
|
|
224
446
|
errors,
|
|
225
447
|
startTime,
|
|
226
|
-
endTime
|
|
448
|
+
endTime,
|
|
227
449
|
};
|
|
228
450
|
}
|
|
229
451
|
selectFirstResult(results) {
|
|
@@ -233,9 +455,121 @@ class ParallelExecutionCoordinator {
|
|
|
233
455
|
const randomIndex = Math.floor(Math.random() * results.length);
|
|
234
456
|
return results[randomIndex];
|
|
235
457
|
}
|
|
236
|
-
async selectResultWithPrompt(results, selectorPromptId) {
|
|
237
|
-
|
|
238
|
-
|
|
458
|
+
async selectResultWithPrompt(results, selectorPromptId, parentPromptRunId, _cancellationToken) {
|
|
459
|
+
try {
|
|
460
|
+
const { AIPromptRunner } = await Promise.resolve().then(() => __importStar(require('./AIPromptRunner')));
|
|
461
|
+
await aiengine_1.AIEngine.Instance.Config(false);
|
|
462
|
+
const judgePrompt = aiengine_1.AIEngine.Instance.Prompts.find((p) => p.ID === selectorPromptId);
|
|
463
|
+
if (!judgePrompt) {
|
|
464
|
+
(0, core_1.LogError)(`Judge prompt with ID ${selectorPromptId} not found`);
|
|
465
|
+
return results[0];
|
|
466
|
+
}
|
|
467
|
+
const judgeData = this.formatResultsForJudge(results);
|
|
468
|
+
const conversationMessages = [
|
|
469
|
+
{
|
|
470
|
+
role: ai_1.ChatMessageRole.system,
|
|
471
|
+
content: 'You are an expert AI judge tasked with ranking multiple AI responses to determine the best one. Analyze each response for quality, accuracy, completeness, and relevance to the original prompt.',
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
role: ai_1.ChatMessageRole.user,
|
|
475
|
+
content: JSON.stringify(judgeData, null, 2),
|
|
476
|
+
},
|
|
477
|
+
];
|
|
478
|
+
let resultSelectorPromptRun = null;
|
|
479
|
+
if (parentPromptRunId) {
|
|
480
|
+
resultSelectorPromptRun = await this.createResultSelectorPromptRun(judgePrompt, judgeData, parentPromptRunId, results.length);
|
|
481
|
+
}
|
|
482
|
+
const judgeRunner = new AIPromptRunner();
|
|
483
|
+
const judgeStartTime = Date.now();
|
|
484
|
+
const judgeResult = await judgeRunner.ExecutePrompt({
|
|
485
|
+
prompt: judgePrompt,
|
|
486
|
+
data: judgeData,
|
|
487
|
+
conversationMessages,
|
|
488
|
+
});
|
|
489
|
+
const judgeEndTime = Date.now();
|
|
490
|
+
const judgeExecutionTimeMS = judgeEndTime - judgeStartTime;
|
|
491
|
+
if (resultSelectorPromptRun && judgeResult.promptRun) {
|
|
492
|
+
resultSelectorPromptRun.CompletedAt = new Date(judgeEndTime);
|
|
493
|
+
resultSelectorPromptRun.ExecutionTimeMS = judgeExecutionTimeMS;
|
|
494
|
+
resultSelectorPromptRun.Success = judgeResult.success;
|
|
495
|
+
resultSelectorPromptRun.Result = judgeResult.rawResult || '';
|
|
496
|
+
if (judgeResult.tokensUsed) {
|
|
497
|
+
resultSelectorPromptRun.TokensUsed = judgeResult.tokensUsed;
|
|
498
|
+
}
|
|
499
|
+
await resultSelectorPromptRun.Save();
|
|
500
|
+
}
|
|
501
|
+
if (!judgeResult.success || !judgeResult.rawResult) {
|
|
502
|
+
(0, core_1.LogError)(`Judge prompt execution failed: ${judgeResult.errorMessage}`);
|
|
503
|
+
return results[0];
|
|
504
|
+
}
|
|
505
|
+
const rankings = this.parseJudgeResult(judgeResult.rawResult);
|
|
506
|
+
if (!rankings || rankings.length === 0) {
|
|
507
|
+
(0, core_1.LogError)('Failed to parse judge rankings');
|
|
508
|
+
return results[0];
|
|
509
|
+
}
|
|
510
|
+
this.applyRankingsToResults(results, rankings);
|
|
511
|
+
const bestCandidateId = rankings.find((r) => r.rank === 1)?.candidateId;
|
|
512
|
+
const bestResultIndex = results.findIndex((r) => r.task.taskId === bestCandidateId);
|
|
513
|
+
const bestResult = bestResultIndex >= 0 ? results[bestResultIndex] : results[0];
|
|
514
|
+
bestResult.judgeMetadata = {
|
|
515
|
+
judgePromptId: selectorPromptId,
|
|
516
|
+
judgeExecutionTimeMS,
|
|
517
|
+
judgeTokensUsed: judgeResult.tokensUsed,
|
|
518
|
+
};
|
|
519
|
+
(0, core_1.LogStatus)(`Judge selected candidate ${bestCandidateId} as the best result`);
|
|
520
|
+
return bestResult;
|
|
521
|
+
}
|
|
522
|
+
catch (error) {
|
|
523
|
+
(0, core_1.LogError)(`Error in AI judge selection: ${error.message}`);
|
|
524
|
+
return results[0];
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
formatResultsForJudge(results) {
|
|
528
|
+
return {
|
|
529
|
+
originalPrompt: results[0]?.task.renderedPrompt || 'Original prompt not available',
|
|
530
|
+
candidates: results.map((result) => ({
|
|
531
|
+
candidateId: result.task.taskId,
|
|
532
|
+
modelName: result.task.model.Name,
|
|
533
|
+
vendorName: result.task.model.Vendor || 'Unknown',
|
|
534
|
+
response: result.rawResult || '',
|
|
535
|
+
executionTimeMS: result.executionTimeMS,
|
|
536
|
+
tokensUsed: result.tokensUsed || 0,
|
|
537
|
+
})),
|
|
538
|
+
instructions: {
|
|
539
|
+
task: 'Rank these AI responses from best to worst (1 = best)',
|
|
540
|
+
format: "Return valid JSON with 'rankings' array containing objects with 'candidateId', 'rank', and 'rationale' fields",
|
|
541
|
+
criteria: ['Quality', 'Accuracy', 'Completeness', 'Relevance', 'Clarity'],
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
parseJudgeResult(judgeResult) {
|
|
546
|
+
try {
|
|
547
|
+
const jsonMatch = judgeResult.match(/\{[\s\S]*\}/);
|
|
548
|
+
const jsonString = jsonMatch ? jsonMatch[0] : judgeResult;
|
|
549
|
+
const parsed = JSON.parse(jsonString);
|
|
550
|
+
if (parsed.rankings && Array.isArray(parsed.rankings)) {
|
|
551
|
+
return parsed.rankings.map((ranking) => ({
|
|
552
|
+
candidateId: ranking.candidateId,
|
|
553
|
+
rank: ranking.rank,
|
|
554
|
+
rationale: ranking.rationale || 'No rationale provided',
|
|
555
|
+
}));
|
|
556
|
+
}
|
|
557
|
+
(0, core_1.LogError)('Judge result does not contain valid rankings array');
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
catch (error) {
|
|
561
|
+
(0, core_1.LogError)(`Failed to parse judge result: ${error.message}`);
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
applyRankingsToResults(results, rankings) {
|
|
566
|
+
for (const result of results) {
|
|
567
|
+
const ranking = rankings.find((r) => r.candidateId === result.task.taskId);
|
|
568
|
+
if (ranking) {
|
|
569
|
+
result.ranking = ranking.rank;
|
|
570
|
+
result.judgeRationale = ranking.rationale;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
239
573
|
}
|
|
240
574
|
selectConsensusResult(results) {
|
|
241
575
|
const resultGroups = new Map();
|
|
@@ -254,8 +588,127 @@ class ParallelExecutionCoordinator {
|
|
|
254
588
|
}
|
|
255
589
|
return largestGroup[0];
|
|
256
590
|
}
|
|
591
|
+
buildMessageArray(renderedPrompt, conversationMessages, templateMessageRole = 'system') {
|
|
592
|
+
const messages = [];
|
|
593
|
+
if (renderedPrompt && templateMessageRole !== 'none') {
|
|
594
|
+
messages.push({
|
|
595
|
+
role: templateMessageRole === 'system' ? ai_1.ChatMessageRole.system : ai_1.ChatMessageRole.user,
|
|
596
|
+
content: renderedPrompt,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
if (conversationMessages && conversationMessages.length > 0) {
|
|
600
|
+
messages.push(...conversationMessages);
|
|
601
|
+
}
|
|
602
|
+
if ((!conversationMessages || conversationMessages.length === 0) && templateMessageRole !== 'user' && renderedPrompt) {
|
|
603
|
+
if (templateMessageRole === 'system') {
|
|
604
|
+
messages.push({
|
|
605
|
+
role: ai_1.ChatMessageRole.user,
|
|
606
|
+
content: 'Please proceed with the above instructions.',
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
else if ((!conversationMessages || conversationMessages.length === 0) && !renderedPrompt) {
|
|
611
|
+
messages.push({
|
|
612
|
+
role: ai_1.ChatMessageRole.user,
|
|
613
|
+
content: 'Hello',
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
return messages;
|
|
617
|
+
}
|
|
618
|
+
async createChildPromptRun(task, startTime, parentPromptRunId, executionOrder) {
|
|
619
|
+
try {
|
|
620
|
+
const promptRun = await this._metadata.GetEntityObject('MJ: AI Prompt Runs', task.contextUser);
|
|
621
|
+
promptRun.NewRecord();
|
|
622
|
+
promptRun.PromptID = task.prompt.ID;
|
|
623
|
+
promptRun.ModelID = task.model.ID;
|
|
624
|
+
promptRun.RunAt = startTime;
|
|
625
|
+
promptRun.RunType = 'ParallelChild';
|
|
626
|
+
promptRun.ParentID = parentPromptRunId;
|
|
627
|
+
if (executionOrder !== undefined) {
|
|
628
|
+
promptRun.ExecutionOrder = executionOrder;
|
|
629
|
+
}
|
|
630
|
+
if (task.promptModel?.VendorID) {
|
|
631
|
+
promptRun.VendorID = task.promptModel.VendorID;
|
|
632
|
+
}
|
|
633
|
+
if (task.configurationId) {
|
|
634
|
+
promptRun.ConfigurationID = task.configurationId;
|
|
635
|
+
}
|
|
636
|
+
const messagesData = {
|
|
637
|
+
renderedPrompt: task.renderedPrompt,
|
|
638
|
+
conversationMessages: task.conversationMessages,
|
|
639
|
+
modelParameters: task.modelParameters,
|
|
640
|
+
taskId: task.taskId,
|
|
641
|
+
};
|
|
642
|
+
promptRun.Messages = JSON.stringify(messagesData);
|
|
643
|
+
const saveResult = await promptRun.Save();
|
|
644
|
+
if (!saveResult) {
|
|
645
|
+
const error = `Failed to save child AIPromptRun: ${promptRun.LatestResult?.Message || 'Unknown error'}`;
|
|
646
|
+
(0, core_1.LogError)(error);
|
|
647
|
+
throw new Error(error);
|
|
648
|
+
}
|
|
649
|
+
return promptRun;
|
|
650
|
+
}
|
|
651
|
+
catch (error) {
|
|
652
|
+
(0, core_1.LogError)(`Error creating child prompt run record: ${error.message}`);
|
|
653
|
+
throw error;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
async updateChildPromptRun(promptRun, modelResult, endTime, executionTimeMS) {
|
|
657
|
+
try {
|
|
658
|
+
promptRun.CompletedAt = endTime;
|
|
659
|
+
promptRun.ExecutionTimeMS = executionTimeMS;
|
|
660
|
+
promptRun.Success = modelResult.success;
|
|
661
|
+
if (modelResult.success) {
|
|
662
|
+
promptRun.Result = modelResult.data?.choices?.[0]?.message?.content || '';
|
|
663
|
+
if (modelResult.data?.usage) {
|
|
664
|
+
promptRun.TokensUsed = modelResult.data.usage.totalTokens;
|
|
665
|
+
promptRun.TokensPrompt = modelResult.data.usage.promptTokens;
|
|
666
|
+
promptRun.TokensCompletion = modelResult.data.usage.completionTokens;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
promptRun.ErrorMessage = modelResult.errorMessage;
|
|
671
|
+
promptRun.Result = `ERROR: ${modelResult.errorMessage}`;
|
|
672
|
+
}
|
|
673
|
+
const saveResult = await promptRun.Save();
|
|
674
|
+
if (!saveResult) {
|
|
675
|
+
(0, core_1.LogError)(`Failed to update child AIPromptRun with results: ${promptRun.LatestResult?.Message || 'Unknown error'}`);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
catch (error) {
|
|
679
|
+
(0, core_1.LogError)(`Error updating child prompt run: ${error.message}`);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
async createResultSelectorPromptRun(judgePrompt, judgeData, parentPromptRunId, executionOrder) {
|
|
683
|
+
try {
|
|
684
|
+
const promptRun = await this._metadata.GetEntityObject('MJ: AI Prompt Runs');
|
|
685
|
+
promptRun.NewRecord();
|
|
686
|
+
promptRun.PromptID = judgePrompt.ID;
|
|
687
|
+
promptRun.RunAt = new Date();
|
|
688
|
+
promptRun.RunType = 'ResultSelector';
|
|
689
|
+
promptRun.ParentID = parentPromptRunId;
|
|
690
|
+
promptRun.ExecutionOrder = executionOrder;
|
|
691
|
+
promptRun.Messages = JSON.stringify({
|
|
692
|
+
judgeData,
|
|
693
|
+
candidateCount: Array.isArray(judgeData.candidates)
|
|
694
|
+
? judgeData.candidates.length
|
|
695
|
+
: 0,
|
|
696
|
+
});
|
|
697
|
+
const saveResult = await promptRun.Save();
|
|
698
|
+
if (!saveResult) {
|
|
699
|
+
const error = `Failed to save ResultSelector AIPromptRun: ${promptRun.LatestResult?.Message || 'Unknown error'}`;
|
|
700
|
+
(0, core_1.LogError)(error);
|
|
701
|
+
throw new Error(error);
|
|
702
|
+
}
|
|
703
|
+
return promptRun;
|
|
704
|
+
}
|
|
705
|
+
catch (error) {
|
|
706
|
+
(0, core_1.LogError)(`Error creating result selector prompt run record: ${error.message}`);
|
|
707
|
+
throw error;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
257
710
|
delay(ms) {
|
|
258
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
711
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
259
712
|
}
|
|
260
713
|
}
|
|
261
714
|
exports.ParallelExecutionCoordinator = ParallelExecutionCoordinator;
|