@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.
@@ -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 allResults = await this.executeGroupsSequentially(executionGroups, executionConfig);
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
- const groupResults = await this.executeGroupInParallel(group, config);
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
- const execution = this.executeTask(task, config);
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
- const completedIndex = executing.findIndex(p => p === Promise.resolve(result));
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
- (0, core_1.LogStatus)(`Group ${group.groupNumber} completed: ${results.filter(r => r.success).length}/${results.length} successful`);
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.messages = [
165
- {
166
- role: ai_1.ChatMessageRole.user,
167
- content: task.renderedPrompt
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 modelResult = await Promise.race([
174
- llm.ChatCompletion(params),
175
- new Promise((_, reject) => setTimeout(() => reject(new Error('Task execution timeout')), timeoutMS))
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
- (0, core_1.LogStatus)(`AI-based result selection not yet implemented, returning first result`);
238
- return results[0];
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;