@memberjunction/ai-prompts 2.111.0 → 2.112.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/dist/AIPromptRunner.d.ts.map +1 -1
- package/dist/AIPromptRunner.js +261 -271
- package/dist/AIPromptRunner.js.map +1 -1
- package/dist/ExecutionPlanner.d.ts +1 -1
- package/dist/ExecutionPlanner.d.ts.map +1 -1
- package/dist/ExecutionPlanner.js +32 -34
- package/dist/ExecutionPlanner.js.map +1 -1
- package/dist/ParallelExecution.d.ts +1 -1
- package/dist/ParallelExecution.d.ts.map +1 -1
- package/dist/ParallelExecutionCoordinator.d.ts.map +1 -1
- package/dist/ParallelExecutionCoordinator.js +31 -31
- package/dist/ParallelExecutionCoordinator.js.map +1 -1
- package/package.json +8 -9
package/dist/AIPromptRunner.js
CHANGED
|
@@ -26,8 +26,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.LoadAIPromptRunner = exports.AIPromptRunner = void 0;
|
|
27
27
|
const ai_1 = require("@memberjunction/ai");
|
|
28
28
|
const ai_core_plus_1 = require("@memberjunction/ai-core-plus");
|
|
29
|
-
const core_1 = require("@memberjunction/core");
|
|
30
29
|
const global_1 = require("@memberjunction/global");
|
|
30
|
+
const global_2 = require("@memberjunction/global");
|
|
31
31
|
const templates_1 = require("@memberjunction/templates");
|
|
32
32
|
const ExecutionPlanner_1 = require("./ExecutionPlanner");
|
|
33
33
|
const ParallelExecutionCoordinator_1 = require("./ParallelExecutionCoordinator");
|
|
@@ -36,11 +36,11 @@ const ai_core_plus_2 = require("@memberjunction/ai-core-plus");
|
|
|
36
36
|
const JSON5 = __importStar(require("json5"));
|
|
37
37
|
class AIPromptRunner {
|
|
38
38
|
constructor() {
|
|
39
|
-
this._metadata = new
|
|
39
|
+
this._metadata = new global_1.Metadata();
|
|
40
40
|
this._templateEngine = templates_1.TemplateEngineServer.Instance;
|
|
41
41
|
this._executionPlanner = new ExecutionPlanner_1.ExecutionPlanner();
|
|
42
42
|
this._parallelCoordinator = new ParallelExecutionCoordinator_1.ParallelExecutionCoordinator();
|
|
43
|
-
this._jsonValidator = new
|
|
43
|
+
this._jsonValidator = new global_2.JSONValidator();
|
|
44
44
|
}
|
|
45
45
|
isValidAPIKey(apiKey) {
|
|
46
46
|
if (apiKey === undefined || apiKey === null) {
|
|
@@ -51,14 +51,14 @@ class AIPromptRunner {
|
|
|
51
51
|
}
|
|
52
52
|
logStatus(message, verboseOnly = false, params) {
|
|
53
53
|
if (verboseOnly) {
|
|
54
|
-
(0,
|
|
54
|
+
(0, global_1.LogStatusEx)({
|
|
55
55
|
message,
|
|
56
56
|
verboseOnly: true,
|
|
57
|
-
isVerboseEnabled: () => params?.verbose === true || (0,
|
|
57
|
+
isVerboseEnabled: () => params?.verbose === true || (0, global_1.IsVerboseLoggingEnabled)(),
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
else {
|
|
61
|
-
(0,
|
|
61
|
+
(0, global_1.LogStatus)(message);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
logError(error, options) {
|
|
@@ -68,7 +68,7 @@ class AIPromptRunner {
|
|
|
68
68
|
errorMessage = errorMessage.substring(0, options.maxErrorLength) + '... [truncated]';
|
|
69
69
|
}
|
|
70
70
|
const metadata = {
|
|
71
|
-
...options?.metadata
|
|
71
|
+
...options?.metadata,
|
|
72
72
|
};
|
|
73
73
|
if (options?.prompt) {
|
|
74
74
|
metadata.promptId = options.prompt.ID;
|
|
@@ -78,18 +78,18 @@ class AIPromptRunner {
|
|
|
78
78
|
metadata.modelId = options.model.ID;
|
|
79
79
|
metadata.modelName = options.model.Name;
|
|
80
80
|
}
|
|
81
|
-
(0,
|
|
81
|
+
(0, global_1.LogErrorEx)({
|
|
82
82
|
message: errorMessage,
|
|
83
83
|
error: errorObj,
|
|
84
84
|
category: options?.category || 'AIPromptRunner',
|
|
85
85
|
severity: options?.severity || 'error',
|
|
86
|
-
metadata: Object.keys(metadata).length > 0 ? metadata : undefined
|
|
86
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
isInferenceProvider(modelVendor) {
|
|
90
|
-
const inferenceProviderType = aiengine_1.AIEngine.Instance.VendorTypeDefinitions.find(vt => vt.Name === 'Inference Provider');
|
|
90
|
+
const inferenceProviderType = aiengine_1.AIEngine.Instance.VendorTypeDefinitions.find((vt) => vt.Name === 'Inference Provider');
|
|
91
91
|
if (!inferenceProviderType) {
|
|
92
|
-
const modelDeveloperType = aiengine_1.AIEngine.Instance.VendorTypeDefinitions.find(vt => vt.Name === 'Model Developer');
|
|
92
|
+
const modelDeveloperType = aiengine_1.AIEngine.Instance.VendorTypeDefinitions.find((vt) => vt.Name === 'Model Developer');
|
|
93
93
|
return modelVendor.TypeID !== modelDeveloperType?.ID;
|
|
94
94
|
}
|
|
95
95
|
return modelVendor.TypeID === inferenceProviderType.ID;
|
|
@@ -107,7 +107,7 @@ class AIPromptRunner {
|
|
|
107
107
|
executionTimeMS: 0,
|
|
108
108
|
chatResult: { success: false, errorMessage: 'Prompt execution was cancelled before starting' },
|
|
109
109
|
tokensUsed: 0,
|
|
110
|
-
combinedTokensUsed: 0
|
|
110
|
+
combinedTokensUsed: 0,
|
|
111
111
|
};
|
|
112
112
|
return result;
|
|
113
113
|
}
|
|
@@ -194,9 +194,9 @@ class AIPromptRunner {
|
|
|
194
194
|
prompt: params.prompt,
|
|
195
195
|
metadata: {
|
|
196
196
|
executionPhase: 'main-execution',
|
|
197
|
-
hasChildPrompts: !!params.childPrompts?.length
|
|
197
|
+
hasChildPrompts: !!params.childPrompts?.length,
|
|
198
198
|
},
|
|
199
|
-
maxErrorLength: params.maxErrorLength
|
|
199
|
+
maxErrorLength: params.maxErrorLength,
|
|
200
200
|
});
|
|
201
201
|
const endTime = new Date();
|
|
202
202
|
const executionTimeMS = endTime.getTime() - startTime.getTime();
|
|
@@ -219,9 +219,9 @@ class AIPromptRunner {
|
|
|
219
219
|
category: 'PromptRunSave',
|
|
220
220
|
metadata: {
|
|
221
221
|
promptRunId: promptRun.ID,
|
|
222
|
-
errorMessage: promptRun.LatestResult?.Message
|
|
222
|
+
errorMessage: promptRun.LatestResult?.Message,
|
|
223
223
|
},
|
|
224
|
-
maxErrorLength: params.maxErrorLength
|
|
224
|
+
maxErrorLength: params.maxErrorLength,
|
|
225
225
|
});
|
|
226
226
|
}
|
|
227
227
|
}
|
|
@@ -232,7 +232,7 @@ class AIPromptRunner {
|
|
|
232
232
|
executionTimeMS,
|
|
233
233
|
chatResult: { success: false, errorMessage: error.message },
|
|
234
234
|
tokensUsed: 0,
|
|
235
|
-
combinedTokensUsed: 0
|
|
235
|
+
combinedTokensUsed: 0,
|
|
236
236
|
};
|
|
237
237
|
return errorResult;
|
|
238
238
|
}
|
|
@@ -250,8 +250,7 @@ class AIPromptRunner {
|
|
|
250
250
|
if (modelSelectionInfo) {
|
|
251
251
|
const vendorID = modelSelectionInfo.vendorSelected?.ID;
|
|
252
252
|
const modelID = modelSelectionInfo.modelSelected.ID;
|
|
253
|
-
const modelVendor = aiengine_1.AIEngine.Instance.ModelVendors.find(mv => mv.VendorID === vendorID &&
|
|
254
|
-
mv.ModelID === modelID);
|
|
253
|
+
const modelVendor = aiengine_1.AIEngine.Instance.ModelVendors.find((mv) => mv.VendorID === vendorID && mv.ModelID === modelID);
|
|
255
254
|
if (modelVendor) {
|
|
256
255
|
vendorDriverClass = modelVendor.DriverClass;
|
|
257
256
|
vendorApiName = modelVendor.APIName;
|
|
@@ -279,7 +278,8 @@ class AIPromptRunner {
|
|
|
279
278
|
if (params.cancellationToken?.aborted) {
|
|
280
279
|
throw new Error('Prompt execution was cancelled after model selection');
|
|
281
280
|
}
|
|
282
|
-
const promptRun = existingPromptRun ||
|
|
281
|
+
const promptRun = existingPromptRun ||
|
|
282
|
+
(await this.createPromptRun(prompt, selectedModel, params, renderedPromptText, startTime, params.override?.vendorId, modelSelectionInfo));
|
|
283
283
|
if (params.cancellationToken?.aborted) {
|
|
284
284
|
throw new Error('Prompt execution was cancelled before model execution');
|
|
285
285
|
}
|
|
@@ -298,13 +298,13 @@ class AIPromptRunner {
|
|
|
298
298
|
executionTimeMS,
|
|
299
299
|
promptTokens: cumulativeTokens.promptTokens || usage?.promptTokens,
|
|
300
300
|
completionTokens: cumulativeTokens.completionTokens || usage?.completionTokens,
|
|
301
|
-
tokensUsed:
|
|
301
|
+
tokensUsed: cumulativeTokens.promptTokens + cumulativeTokens.completionTokens || (usage?.promptTokens || 0) + (usage?.completionTokens || 0),
|
|
302
302
|
cost: cumulativeTokens.totalCost || usage?.cost,
|
|
303
303
|
costCurrency: usage?.costCurrency,
|
|
304
304
|
validationResult: parsedResult.validationResult,
|
|
305
305
|
validationAttempts,
|
|
306
|
-
combinedTokensUsed:
|
|
307
|
-
modelSelectionInfo
|
|
306
|
+
combinedTokensUsed: cumulativeTokens.promptTokens + cumulativeTokens.completionTokens || (usage?.promptTokens || 0) + (usage?.completionTokens || 0),
|
|
307
|
+
modelSelectionInfo,
|
|
308
308
|
};
|
|
309
309
|
}
|
|
310
310
|
async executePromptInParallel(prompt, renderedPromptText, params, startTime, existingPromptRun, existingModel, existingModelSelectionInfo) {
|
|
@@ -314,7 +314,8 @@ class AIPromptRunner {
|
|
|
314
314
|
await aiengine_1.AIEngine.Instance.Config(false, params.contextUser);
|
|
315
315
|
let executionTasks;
|
|
316
316
|
if (existingModel) {
|
|
317
|
-
executionTasks = [
|
|
317
|
+
executionTasks = [
|
|
318
|
+
{
|
|
318
319
|
taskId: 'pre-selected',
|
|
319
320
|
model: existingModel,
|
|
320
321
|
vendorDriverClass: undefined,
|
|
@@ -322,8 +323,9 @@ class AIPromptRunner {
|
|
|
322
323
|
messages: params.conversationMessages || [],
|
|
323
324
|
promptText: renderedPromptText,
|
|
324
325
|
templateMessageRole: params.templateMessageRole || 'system',
|
|
325
|
-
contextUser: params.contextUser
|
|
326
|
-
}
|
|
326
|
+
contextUser: params.contextUser,
|
|
327
|
+
},
|
|
328
|
+
];
|
|
327
329
|
this.logStatus(` Using pre-selected model "${existingModel.Name}" for parallel execution`, true, params);
|
|
328
330
|
}
|
|
329
331
|
else {
|
|
@@ -377,7 +379,8 @@ class AIPromptRunner {
|
|
|
377
379
|
}
|
|
378
380
|
}
|
|
379
381
|
}
|
|
380
|
-
const consolidatedPromptRun = existingPromptRun ||
|
|
382
|
+
const consolidatedPromptRun = existingPromptRun ||
|
|
383
|
+
(await this.createPromptRun(prompt, selectedResult.task.model, params, renderedPromptText, startTime, params.override?.vendorId, existingModelSelectionInfo));
|
|
381
384
|
const endTime = new Date();
|
|
382
385
|
consolidatedPromptRun.CompletedAt = endTime;
|
|
383
386
|
consolidatedPromptRun.ExecutionTimeMS = parallelResult.totalExecutionTimeMS;
|
|
@@ -425,9 +428,9 @@ class AIPromptRunner {
|
|
|
425
428
|
metadata: {
|
|
426
429
|
promptRunId: consolidatedPromptRun.ID,
|
|
427
430
|
executionTasks: executionTasks.length,
|
|
428
|
-
successfulResults: successfulResults.length
|
|
431
|
+
successfulResults: successfulResults.length,
|
|
429
432
|
},
|
|
430
|
-
maxErrorLength: params.maxErrorLength
|
|
433
|
+
maxErrorLength: params.maxErrorLength,
|
|
431
434
|
});
|
|
432
435
|
}
|
|
433
436
|
const additionalResults = [];
|
|
@@ -462,7 +465,7 @@ class AIPromptRunner {
|
|
|
462
465
|
vendorId: undefined,
|
|
463
466
|
vendorName: result.task.model.Vendor,
|
|
464
467
|
},
|
|
465
|
-
combinedTokensUsed: (resultUsage?.promptTokens || 0) + (resultUsage?.completionTokens || 0)
|
|
468
|
+
combinedTokensUsed: (resultUsage?.promptTokens || 0) + (resultUsage?.completionTokens || 0),
|
|
466
469
|
});
|
|
467
470
|
}
|
|
468
471
|
}
|
|
@@ -509,8 +512,8 @@ class AIPromptRunner {
|
|
|
509
512
|
category: 'TemplateLoading',
|
|
510
513
|
metadata: {
|
|
511
514
|
templateId,
|
|
512
|
-
phase: 'lookup'
|
|
513
|
-
}
|
|
515
|
+
phase: 'lookup',
|
|
516
|
+
},
|
|
514
517
|
});
|
|
515
518
|
return null;
|
|
516
519
|
}
|
|
@@ -518,7 +521,7 @@ class AIPromptRunner {
|
|
|
518
521
|
async renderChildPromptTemplates(childPrompts, params, cancellationToken) {
|
|
519
522
|
if (!childPrompts || childPrompts.length === 0) {
|
|
520
523
|
return {
|
|
521
|
-
renderedTemplates: {}
|
|
524
|
+
renderedTemplates: {},
|
|
522
525
|
};
|
|
523
526
|
}
|
|
524
527
|
if (cancellationToken?.aborted) {
|
|
@@ -545,13 +548,13 @@ class AIPromptRunner {
|
|
|
545
548
|
const mergedChildData = {
|
|
546
549
|
...params.data,
|
|
547
550
|
...childData,
|
|
548
|
-
...childParam.childPrompt.templateData
|
|
551
|
+
...childParam.childPrompt.templateData,
|
|
549
552
|
};
|
|
550
553
|
const childRenderResult = await this.renderPromptTemplate(template, {
|
|
551
554
|
...params,
|
|
552
555
|
prompt: childPrompt,
|
|
553
556
|
data: mergedChildData,
|
|
554
|
-
templateData: childParam.childPrompt.templateData
|
|
557
|
+
templateData: childParam.childPrompt.templateData,
|
|
555
558
|
});
|
|
556
559
|
if (!childRenderResult.Success) {
|
|
557
560
|
throw new Error(`Failed to render child template for prompt ${childPrompt.Name}: ${childRenderResult.Message}`);
|
|
@@ -564,26 +567,26 @@ class AIPromptRunner {
|
|
|
564
567
|
return {
|
|
565
568
|
placeholder: childParam.parentPlaceholder,
|
|
566
569
|
renderedTemplate: renderedChildTemplate,
|
|
567
|
-
success: true
|
|
570
|
+
success: true,
|
|
568
571
|
};
|
|
569
572
|
}
|
|
570
573
|
catch (error) {
|
|
571
574
|
this.logError(error, {
|
|
572
575
|
category: 'ChildTemplateRendering',
|
|
573
576
|
metadata: {
|
|
574
|
-
placeholder: childParam.parentPlaceholder
|
|
577
|
+
placeholder: childParam.parentPlaceholder,
|
|
575
578
|
},
|
|
576
|
-
maxErrorLength: params.maxErrorLength
|
|
579
|
+
maxErrorLength: params.maxErrorLength,
|
|
577
580
|
});
|
|
578
581
|
return {
|
|
579
582
|
placeholder: childParam.parentPlaceholder,
|
|
580
583
|
renderedTemplate: `ERROR: ${error.message}`,
|
|
581
|
-
success: false
|
|
584
|
+
success: false,
|
|
582
585
|
};
|
|
583
586
|
}
|
|
584
587
|
});
|
|
585
588
|
const childResults = await Promise.all(childRenderingPromises);
|
|
586
|
-
const failedChildren = childResults.filter(r => !r.success);
|
|
589
|
+
const failedChildren = childResults.filter((r) => !r.success);
|
|
587
590
|
if (failedChildren.length > 0) {
|
|
588
591
|
this.logError(`${failedChildren.length} out of ${childResults.length} child prompt templates failed to render`, {
|
|
589
592
|
category: 'ChildTemplateFailures',
|
|
@@ -591,18 +594,18 @@ class AIPromptRunner {
|
|
|
591
594
|
metadata: {
|
|
592
595
|
failedCount: failedChildren.length,
|
|
593
596
|
totalCount: childResults.length,
|
|
594
|
-
failedPlaceholders: failedChildren.map(fc => fc.placeholder)
|
|
597
|
+
failedPlaceholders: failedChildren.map((fc) => fc.placeholder),
|
|
595
598
|
},
|
|
596
|
-
maxErrorLength: params.maxErrorLength
|
|
599
|
+
maxErrorLength: params.maxErrorLength,
|
|
597
600
|
});
|
|
598
|
-
throw new Error(`Failed to render ${failedChildren.length} child prompt templates: ${failedChildren.map(fc => fc.placeholder).join(', ')}`);
|
|
601
|
+
throw new Error(`Failed to render ${failedChildren.length} child prompt templates: ${failedChildren.map((fc) => fc.placeholder).join(', ')}`);
|
|
599
602
|
}
|
|
600
603
|
const renderedTemplatesMap = {};
|
|
601
604
|
for (const childResult of childResults) {
|
|
602
605
|
renderedTemplatesMap[childResult.placeholder] = childResult.renderedTemplate;
|
|
603
606
|
}
|
|
604
607
|
return {
|
|
605
|
-
renderedTemplates: renderedTemplatesMap
|
|
608
|
+
renderedTemplates: renderedTemplatesMap,
|
|
606
609
|
};
|
|
607
610
|
}
|
|
608
611
|
async renderPromptWithChildTemplates(prompt, params, childTemplates) {
|
|
@@ -620,7 +623,7 @@ class AIPromptRunner {
|
|
|
620
623
|
...systemPlaceholders,
|
|
621
624
|
...params.data,
|
|
622
625
|
...childTemplates,
|
|
623
|
-
...params.templateData
|
|
626
|
+
...params.templateData,
|
|
624
627
|
};
|
|
625
628
|
this.logStatus(` 🔧 ${prompt.Name} [Rendering Prompt Template]`, true, params);
|
|
626
629
|
for (const [placeholder, template] of Object.entries(childTemplates)) {
|
|
@@ -638,9 +641,9 @@ class AIPromptRunner {
|
|
|
638
641
|
prompt: prompt,
|
|
639
642
|
metadata: {
|
|
640
643
|
childPromptCount: params.childPrompts?.length || 0,
|
|
641
|
-
templateId: prompt.TemplateID
|
|
644
|
+
templateId: prompt.TemplateID,
|
|
642
645
|
},
|
|
643
|
-
maxErrorLength: params.maxErrorLength
|
|
646
|
+
maxErrorLength: params.maxErrorLength,
|
|
644
647
|
});
|
|
645
648
|
throw error;
|
|
646
649
|
}
|
|
@@ -661,7 +664,7 @@ class AIPromptRunner {
|
|
|
661
664
|
selectionStrategy = 'ByPower';
|
|
662
665
|
}
|
|
663
666
|
if (configurationId) {
|
|
664
|
-
configuration = aiengine_1.AIEngine.Instance.Configurations.find(c => c.ID === configurationId);
|
|
667
|
+
configuration = aiengine_1.AIEngine.Instance.Configurations.find((c) => c.ID === configurationId);
|
|
665
668
|
configurationName = configuration?.Name;
|
|
666
669
|
}
|
|
667
670
|
const candidates = this.buildModelVendorCandidates(prompt, explicitModelId, configurationId, vendorId, params.verbose);
|
|
@@ -671,7 +674,7 @@ class AIPromptRunner {
|
|
|
671
674
|
category: 'ModelSelection',
|
|
672
675
|
prompt: prompt,
|
|
673
676
|
severity: 'critical',
|
|
674
|
-
maxErrorLength: params?.maxErrorLength
|
|
677
|
+
maxErrorLength: params?.maxErrorLength,
|
|
675
678
|
});
|
|
676
679
|
return {
|
|
677
680
|
model: null,
|
|
@@ -685,8 +688,8 @@ class AIPromptRunner {
|
|
|
685
688
|
modelSelected: undefined,
|
|
686
689
|
selectionReason: 'No suitable model candidates found',
|
|
687
690
|
fallbackUsed: false,
|
|
688
|
-
selectionStrategy
|
|
689
|
-
})
|
|
691
|
+
selectionStrategy,
|
|
692
|
+
}),
|
|
690
693
|
};
|
|
691
694
|
}
|
|
692
695
|
const { selected, consideredModels } = await this.selectModelWithAPIKeyTracked(candidates, params);
|
|
@@ -704,8 +707,8 @@ class AIPromptRunner {
|
|
|
704
707
|
modelSelected: undefined,
|
|
705
708
|
selectionReason: 'No API keys found for any model-vendor combination',
|
|
706
709
|
fallbackUsed: false,
|
|
707
|
-
selectionStrategy
|
|
708
|
-
})
|
|
710
|
+
selectionStrategy,
|
|
711
|
+
}),
|
|
709
712
|
};
|
|
710
713
|
}
|
|
711
714
|
let selectionReason = `Selected ${selected.model.Name} via ${selected.vendorName || 'default vendor'}`;
|
|
@@ -727,7 +730,7 @@ class AIPromptRunner {
|
|
|
727
730
|
const fallbackUsed = candidates.indexOf(selected) > 0;
|
|
728
731
|
let selectedVendor;
|
|
729
732
|
if (selected.vendorId) {
|
|
730
|
-
selectedVendor = aiengine_1.AIEngine.Instance.Vendors.find(v => v.ID === selected.vendorId);
|
|
733
|
+
selectedVendor = aiengine_1.AIEngine.Instance.Vendors.find((v) => v.ID === selected.vendorId);
|
|
731
734
|
}
|
|
732
735
|
return {
|
|
733
736
|
model: selected.model,
|
|
@@ -742,15 +745,15 @@ class AIPromptRunner {
|
|
|
742
745
|
vendorSelected: selectedVendor,
|
|
743
746
|
selectionReason,
|
|
744
747
|
fallbackUsed,
|
|
745
|
-
selectionStrategy
|
|
746
|
-
})
|
|
748
|
+
selectionStrategy,
|
|
749
|
+
}),
|
|
747
750
|
};
|
|
748
751
|
}
|
|
749
752
|
catch (error) {
|
|
750
753
|
this.logError(error, {
|
|
751
754
|
category: 'ModelSelection',
|
|
752
755
|
prompt: prompt,
|
|
753
|
-
maxErrorLength: params?.maxErrorLength
|
|
756
|
+
maxErrorLength: params?.maxErrorLength,
|
|
754
757
|
});
|
|
755
758
|
return {
|
|
756
759
|
model: null,
|
|
@@ -764,21 +767,18 @@ class AIPromptRunner {
|
|
|
764
767
|
modelSelected: undefined,
|
|
765
768
|
selectionReason: `Error during model selection: ${error.message}`,
|
|
766
769
|
fallbackUsed: false,
|
|
767
|
-
selectionStrategy: 'Default'
|
|
768
|
-
})
|
|
770
|
+
selectionStrategy: 'Default',
|
|
771
|
+
}),
|
|
769
772
|
};
|
|
770
773
|
}
|
|
771
774
|
}
|
|
772
775
|
buildModelVendorCandidates(prompt, explicitModelId, configurationId, preferredVendorId, verbose) {
|
|
773
|
-
const preferredVendorName = preferredVendorId ?
|
|
774
|
-
aiengine_1.AIEngine.Instance.Vendors.find(v => v.ID === preferredVendorId)?.Name : undefined;
|
|
776
|
+
const preferredVendorName = preferredVendorId ? aiengine_1.AIEngine.Instance.Vendors.find((v) => v.ID === preferredVendorId)?.Name : undefined;
|
|
775
777
|
const createCandidatesForModel = (model, basePriority, source, promptModelPriority) => {
|
|
776
778
|
const modelCandidates = [];
|
|
777
|
-
const modelVendors = aiengine_1.AIEngine.Instance.ModelVendors
|
|
778
|
-
.filter(mv => mv.ModelID === model.ID && mv.Status === 'Active' && this.isInferenceProvider(mv))
|
|
779
|
-
.sort((a, b) => b.Priority - a.Priority);
|
|
779
|
+
const modelVendors = aiengine_1.AIEngine.Instance.ModelVendors.filter((mv) => mv.ModelID === model.ID && mv.Status === 'Active' && this.isInferenceProvider(mv)).sort((a, b) => b.Priority - a.Priority);
|
|
780
780
|
if (preferredVendorId) {
|
|
781
|
-
const preferredVendor = modelVendors.find(mv => mv.VendorID === preferredVendorId);
|
|
781
|
+
const preferredVendor = modelVendors.find((mv) => mv.VendorID === preferredVendorId);
|
|
782
782
|
if (preferredVendor) {
|
|
783
783
|
modelCandidates.push({
|
|
784
784
|
model,
|
|
@@ -789,7 +789,7 @@ class AIPromptRunner {
|
|
|
789
789
|
supportsEffortLevel: preferredVendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
790
790
|
isPreferredVendor: true,
|
|
791
791
|
priority: basePriority + 1000,
|
|
792
|
-
source
|
|
792
|
+
source,
|
|
793
793
|
});
|
|
794
794
|
}
|
|
795
795
|
}
|
|
@@ -804,7 +804,7 @@ class AIPromptRunner {
|
|
|
804
804
|
supportsEffortLevel: vendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
805
805
|
isPreferredVendor: false,
|
|
806
806
|
priority: basePriority + (vendor.Priority || 0),
|
|
807
|
-
source
|
|
807
|
+
source,
|
|
808
808
|
});
|
|
809
809
|
}
|
|
810
810
|
}
|
|
@@ -816,22 +816,21 @@ class AIPromptRunner {
|
|
|
816
816
|
supportsEffortLevel: model.SupportsEffortLevel ?? false,
|
|
817
817
|
isPreferredVendor: false,
|
|
818
818
|
priority: basePriority,
|
|
819
|
-
source
|
|
819
|
+
source,
|
|
820
820
|
});
|
|
821
821
|
}
|
|
822
822
|
if (promptModelPriority !== undefined) {
|
|
823
|
-
modelCandidates.forEach(c => c.priority += promptModelPriority * 10);
|
|
823
|
+
modelCandidates.forEach((c) => (c.priority += promptModelPriority * 10));
|
|
824
824
|
}
|
|
825
825
|
return modelCandidates;
|
|
826
826
|
};
|
|
827
827
|
const createSpecificCandidatesForModel = (model, promptModel, preferredVendorId) => {
|
|
828
828
|
const modelCandidates = [];
|
|
829
829
|
const basePriority = 10000 + (promptModel.Priority || 0) * 100;
|
|
830
|
-
const modelVendors = aiengine_1.AIEngine.Instance.ModelVendors
|
|
831
|
-
.filter(mv => mv.ModelID === model.ID && mv.Status === 'Active' && this.isInferenceProvider(mv));
|
|
830
|
+
const modelVendors = aiengine_1.AIEngine.Instance.ModelVendors.filter((mv) => mv.ModelID === model.ID && mv.Status === 'Active' && this.isInferenceProvider(mv));
|
|
832
831
|
const pmPreferredVendorId = promptModel.VendorID || preferredVendorId;
|
|
833
832
|
if (pmPreferredVendorId) {
|
|
834
|
-
const preferredVendor = modelVendors.find(mv => mv.VendorID === pmPreferredVendorId);
|
|
833
|
+
const preferredVendor = modelVendors.find((mv) => mv.VendorID === pmPreferredVendorId);
|
|
835
834
|
if (preferredVendor) {
|
|
836
835
|
modelCandidates.push({
|
|
837
836
|
model,
|
|
@@ -842,7 +841,7 @@ class AIPromptRunner {
|
|
|
842
841
|
supportsEffortLevel: preferredVendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
843
842
|
isPreferredVendor: true,
|
|
844
843
|
priority: basePriority + 1000,
|
|
845
|
-
source: 'prompt-model'
|
|
844
|
+
source: 'prompt-model',
|
|
846
845
|
});
|
|
847
846
|
}
|
|
848
847
|
}
|
|
@@ -857,7 +856,7 @@ class AIPromptRunner {
|
|
|
857
856
|
supportsEffortLevel: vendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
858
857
|
isPreferredVendor: false,
|
|
859
858
|
priority: basePriority + (vendor.Priority || 0) * 10,
|
|
860
|
-
source: 'prompt-model'
|
|
859
|
+
source: 'prompt-model',
|
|
861
860
|
});
|
|
862
861
|
}
|
|
863
862
|
}
|
|
@@ -869,13 +868,13 @@ class AIPromptRunner {
|
|
|
869
868
|
supportsEffortLevel: model.SupportsEffortLevel ?? false,
|
|
870
869
|
isPreferredVendor: false,
|
|
871
870
|
priority: basePriority,
|
|
872
|
-
source: 'prompt-model'
|
|
871
|
+
source: 'prompt-model',
|
|
873
872
|
});
|
|
874
873
|
}
|
|
875
874
|
return modelCandidates;
|
|
876
875
|
};
|
|
877
876
|
if (explicitModelId) {
|
|
878
|
-
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === explicitModelId);
|
|
877
|
+
const model = aiengine_1.AIEngine.Instance.Models.find((m) => m.ID === explicitModelId);
|
|
879
878
|
if (model && model.IsActive) {
|
|
880
879
|
if (!prompt.AIModelTypeID || model.AIModelTypeID === prompt.AIModelTypeID) {
|
|
881
880
|
const candidates = createCandidatesForModel(model, 20000, 'explicit');
|
|
@@ -887,26 +886,20 @@ class AIPromptRunner {
|
|
|
887
886
|
}
|
|
888
887
|
let promptModels = [];
|
|
889
888
|
if (configurationId) {
|
|
890
|
-
promptModels = aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
891
|
-
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
892
|
-
pm.ConfigurationID === configurationId);
|
|
889
|
+
promptModels = aiengine_1.AIEngine.Instance.PromptModels.filter((pm) => pm.PromptID === prompt.ID && (pm.Status === 'Active' || pm.Status === 'Preview') && pm.ConfigurationID === configurationId);
|
|
893
890
|
if (promptModels.length === 0) {
|
|
894
|
-
(0,
|
|
895
|
-
promptModels = aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
896
|
-
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
897
|
-
!pm.ConfigurationID);
|
|
891
|
+
(0, global_1.LogStatus)(`No models found for configuration "${configurationId}", falling back to default models`);
|
|
892
|
+
promptModels = aiengine_1.AIEngine.Instance.PromptModels.filter((pm) => pm.PromptID === prompt.ID && (pm.Status === 'Active' || pm.Status === 'Preview') && !pm.ConfigurationID);
|
|
898
893
|
}
|
|
899
894
|
}
|
|
900
895
|
else {
|
|
901
|
-
promptModels = aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
902
|
-
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
903
|
-
!pm.ConfigurationID);
|
|
896
|
+
promptModels = aiengine_1.AIEngine.Instance.PromptModels.filter((pm) => pm.PromptID === prompt.ID && (pm.Status === 'Active' || pm.Status === 'Preview') && !pm.ConfigurationID);
|
|
904
897
|
}
|
|
905
898
|
if (prompt.SelectionStrategy === 'Specific' && promptModels.length > 0) {
|
|
906
899
|
const candidates = [];
|
|
907
900
|
promptModels.sort((a, b) => (b.Priority || 0) - (a.Priority || 0));
|
|
908
901
|
for (const pm of promptModels) {
|
|
909
|
-
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === pm.ModelID);
|
|
902
|
+
const model = aiengine_1.AIEngine.Instance.Models.find((m) => m.ID === pm.ModelID);
|
|
910
903
|
if (model && model.IsActive) {
|
|
911
904
|
const modelCandidates = createSpecificCandidatesForModel(model, pm, preferredVendorId);
|
|
912
905
|
candidates.push(...modelCandidates);
|
|
@@ -915,32 +908,30 @@ class AIPromptRunner {
|
|
|
915
908
|
if (candidates.length > 0) {
|
|
916
909
|
candidates.sort((a, b) => b.priority - a.priority);
|
|
917
910
|
if (verbose) {
|
|
918
|
-
(0,
|
|
911
|
+
(0, global_1.LogStatus)(`Using SelectionStrategy='Specific' with ${promptModels.length} AIPromptModel entries, generated ${candidates.length} candidates`);
|
|
919
912
|
}
|
|
920
913
|
return candidates;
|
|
921
914
|
}
|
|
922
915
|
if (verbose) {
|
|
923
|
-
(0,
|
|
916
|
+
(0, global_1.LogStatus)(`SelectionStrategy='Specific' specified but no usable candidates from AIPromptModel entries, falling back to general selection`);
|
|
924
917
|
}
|
|
925
918
|
}
|
|
926
919
|
const candidates = [];
|
|
927
920
|
if (promptModels.length > 0 && prompt.SelectionStrategy !== 'Specific') {
|
|
928
921
|
for (const pm of promptModels) {
|
|
929
|
-
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === pm.ModelID);
|
|
922
|
+
const model = aiengine_1.AIEngine.Instance.Models.find((m) => m.ID === pm.ModelID);
|
|
930
923
|
if (model && model.IsActive) {
|
|
931
924
|
const modelCandidates = createCandidatesForModel(model, 5000, 'prompt-model', pm.Priority);
|
|
932
925
|
candidates.push(...modelCandidates);
|
|
933
926
|
}
|
|
934
927
|
}
|
|
935
928
|
if (configurationId) {
|
|
936
|
-
const nullConfigModels = aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
937
|
-
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
938
|
-
!pm.ConfigurationID);
|
|
929
|
+
const nullConfigModels = aiengine_1.AIEngine.Instance.PromptModels.filter((pm) => pm.PromptID === prompt.ID && (pm.Status === 'Active' || pm.Status === 'Preview') && !pm.ConfigurationID);
|
|
939
930
|
if (nullConfigModels.length > 0 && verbose) {
|
|
940
|
-
(0,
|
|
931
|
+
(0, global_1.LogStatus)(`Adding ${nullConfigModels.length} NULL configuration models as fallback candidates`);
|
|
941
932
|
}
|
|
942
933
|
for (const pm of nullConfigModels) {
|
|
943
|
-
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === pm.ModelID);
|
|
934
|
+
const model = aiengine_1.AIEngine.Instance.Models.find((m) => m.ID === pm.ModelID);
|
|
944
935
|
if (model && model.IsActive) {
|
|
945
936
|
const modelCandidates = createCandidatesForModel(model, 2000, 'prompt-model', pm.Priority);
|
|
946
937
|
candidates.push(...modelCandidates);
|
|
@@ -949,13 +940,10 @@ class AIPromptRunner {
|
|
|
949
940
|
}
|
|
950
941
|
}
|
|
951
942
|
else {
|
|
952
|
-
let modelPool = aiengine_1.AIEngine.Instance.Models.filter(m => m.IsActive &&
|
|
943
|
+
let modelPool = aiengine_1.AIEngine.Instance.Models.filter((m) => m.IsActive &&
|
|
953
944
|
(!prompt.AIModelTypeID || m.AIModelTypeID === prompt.AIModelTypeID) &&
|
|
954
945
|
(!preferredVendorName ||
|
|
955
|
-
aiengine_1.AIEngine.Instance.ModelVendors.some(mv => mv.ModelID === m.ID &&
|
|
956
|
-
mv.Status === 'Active' &&
|
|
957
|
-
mv.Vendor === preferredVendorName &&
|
|
958
|
-
this.isInferenceProvider(mv))));
|
|
946
|
+
aiengine_1.AIEngine.Instance.ModelVendors.some((mv) => mv.ModelID === m.ID && mv.Status === 'Active' && mv.Vendor === preferredVendorName && this.isInferenceProvider(mv))));
|
|
959
947
|
switch (prompt.SelectionStrategy) {
|
|
960
948
|
case 'ByPower':
|
|
961
949
|
switch (prompt.PowerPreference) {
|
|
@@ -975,7 +963,7 @@ class AIPromptRunner {
|
|
|
975
963
|
case 'Default':
|
|
976
964
|
default:
|
|
977
965
|
const minPowerRank = prompt.MinPowerRank || 0;
|
|
978
|
-
modelPool = modelPool.filter(m => m.PowerRank >= minPowerRank);
|
|
966
|
+
modelPool = modelPool.filter((m) => m.PowerRank >= minPowerRank);
|
|
979
967
|
modelPool.sort((a, b) => b.PowerRank - a.PowerRank);
|
|
980
968
|
break;
|
|
981
969
|
}
|
|
@@ -994,10 +982,10 @@ class AIPromptRunner {
|
|
|
994
982
|
}
|
|
995
983
|
buildCandidatesFromSelectionInfo(selectionInfo) {
|
|
996
984
|
const validModels = selectionInfo.extractValidCandidates();
|
|
997
|
-
return validModels
|
|
985
|
+
return validModels
|
|
986
|
+
.map((considered) => {
|
|
998
987
|
const modelVendor = considered.vendor
|
|
999
|
-
? aiengine_1.AIEngine.Instance.ModelVendors.find(mv => mv.ModelID === considered.model.ID &&
|
|
1000
|
-
mv.VendorID === considered.vendor.ID)
|
|
988
|
+
? aiengine_1.AIEngine.Instance.ModelVendors.find((mv) => mv.ModelID === considered.model.ID && mv.VendorID === considered.vendor.ID)
|
|
1001
989
|
: undefined;
|
|
1002
990
|
return {
|
|
1003
991
|
model: considered.model,
|
|
@@ -1008,9 +996,10 @@ class AIPromptRunner {
|
|
|
1008
996
|
supportsEffortLevel: modelVendor?.SupportsEffortLevel ?? considered.model.SupportsEffortLevel ?? false,
|
|
1009
997
|
isPreferredVendor: false,
|
|
1010
998
|
priority: considered.priority,
|
|
1011
|
-
source: (selectionInfo.selectionStrategy === 'ByPower' ? 'power-rank' : 'model-type')
|
|
999
|
+
source: (selectionInfo.selectionStrategy === 'ByPower' ? 'power-rank' : 'model-type'),
|
|
1012
1000
|
};
|
|
1013
|
-
})
|
|
1001
|
+
})
|
|
1002
|
+
.sort((a, b) => b.priority - a.priority);
|
|
1014
1003
|
}
|
|
1015
1004
|
async selectModelWithAPIKeyTracked(candidates, params) {
|
|
1016
1005
|
const checkedDrivers = new Map();
|
|
@@ -1027,21 +1016,22 @@ class AIPromptRunner {
|
|
|
1027
1016
|
}
|
|
1028
1017
|
let vendorEntity;
|
|
1029
1018
|
if (candidate.vendorId) {
|
|
1030
|
-
vendorEntity = aiengine_1.AIEngine.Instance.Vendors.find(v => v.ID === candidate.vendorId);
|
|
1019
|
+
vendorEntity = aiengine_1.AIEngine.Instance.Vendors.find((v) => v.ID === candidate.vendorId);
|
|
1031
1020
|
}
|
|
1032
1021
|
consideredModels.push({
|
|
1033
1022
|
model: candidate.model,
|
|
1034
1023
|
vendor: vendorEntity,
|
|
1035
1024
|
priority: candidate.priority,
|
|
1036
1025
|
available: hasKey,
|
|
1037
|
-
unavailableReason: hasKey ? undefined : `No API key for driver ${candidate.driverClass}
|
|
1026
|
+
unavailableReason: hasKey ? undefined : `No API key for driver ${candidate.driverClass}`,
|
|
1038
1027
|
});
|
|
1039
1028
|
}
|
|
1040
|
-
const selected = consideredModels.find(m => m.available);
|
|
1041
|
-
const selectedCandidate = selected
|
|
1042
|
-
c.vendorId === selected.vendor?.ID)
|
|
1029
|
+
const selected = consideredModels.find((m) => m.available);
|
|
1030
|
+
const selectedCandidate = selected
|
|
1031
|
+
? candidates.find((c) => c.model.ID === selected.model.ID && c.vendorId === selected.vendor?.ID)
|
|
1032
|
+
: null;
|
|
1043
1033
|
if (selectedCandidate) {
|
|
1044
|
-
const validCount = consideredModels.filter(m => m.available).length;
|
|
1034
|
+
const validCount = consideredModels.filter((m) => m.available).length;
|
|
1045
1035
|
this.logStatus(` Selected model ${selectedCandidate.model.Name} with ${selectedCandidate.vendorName || 'default'} vendor (driver: ${selectedCandidate.driverClass})`, true);
|
|
1046
1036
|
if (selectedCandidate.isPreferredVendor) {
|
|
1047
1037
|
this.logStatus(` Using preferred vendor${selectedCandidate.vendorId ? ` (${selectedCandidate.vendorName})` : ''}`, true, params);
|
|
@@ -1049,15 +1039,18 @@ class AIPromptRunner {
|
|
|
1049
1039
|
this.logStatus(` Found ${validCount} valid candidate(s) out of ${candidates.length} total`, true, params);
|
|
1050
1040
|
}
|
|
1051
1041
|
else {
|
|
1052
|
-
const triedSummary = candidates
|
|
1042
|
+
const triedSummary = candidates
|
|
1043
|
+
.slice(0, 5)
|
|
1044
|
+
.map((c) => `${c.model.Name}/${c.vendorName || 'default'}(${c.driverClass})`)
|
|
1045
|
+
.join(', ');
|
|
1053
1046
|
this.logError(`No API keys found for any model-vendor combination. Tried: ${triedSummary}${candidates.length > 5 ? `... (${candidates.length} total)` : ''}`, {
|
|
1054
1047
|
category: 'APIKeyValidation',
|
|
1055
1048
|
severity: 'critical',
|
|
1056
1049
|
metadata: {
|
|
1057
1050
|
candidatesChecked: candidates.length,
|
|
1058
|
-
modelsChecked: consideredModels.length
|
|
1051
|
+
modelsChecked: consideredModels.length,
|
|
1059
1052
|
},
|
|
1060
|
-
maxErrorLength: params?.maxErrorLength
|
|
1053
|
+
maxErrorLength: params?.maxErrorLength,
|
|
1061
1054
|
});
|
|
1062
1055
|
}
|
|
1063
1056
|
return { selected: selectedCandidate, consideredModels };
|
|
@@ -1077,20 +1070,20 @@ class AIPromptRunner {
|
|
|
1077
1070
|
const dbSelectionInfo = {
|
|
1078
1071
|
configurationId: modelSelectionInfo.aiConfiguration?.ID,
|
|
1079
1072
|
configurationName: modelSelectionInfo.aiConfiguration?.Name,
|
|
1080
|
-
modelsConsidered: modelSelectionInfo.modelsConsidered.map(mc => ({
|
|
1073
|
+
modelsConsidered: modelSelectionInfo.modelsConsidered.map((mc) => ({
|
|
1081
1074
|
modelId: mc.model.ID,
|
|
1082
1075
|
modelName: mc.model.Name,
|
|
1083
1076
|
vendorId: mc.vendor?.ID,
|
|
1084
1077
|
vendorName: mc.vendor?.Name || 'default',
|
|
1085
1078
|
priority: mc.priority,
|
|
1086
1079
|
available: mc.available,
|
|
1087
|
-
unavailableReason: mc.unavailableReason
|
|
1080
|
+
unavailableReason: mc.unavailableReason,
|
|
1088
1081
|
})),
|
|
1089
1082
|
modelSelected: modelSelectionInfo.modelSelected?.ID,
|
|
1090
1083
|
vendorSelected: modelSelectionInfo.vendorSelected?.ID,
|
|
1091
1084
|
selectionReason: modelSelectionInfo.selectionReason,
|
|
1092
1085
|
fallbackUsed: modelSelectionInfo.fallbackUsed,
|
|
1093
|
-
selectionStrategy: modelSelectionInfo.selectionStrategy
|
|
1086
|
+
selectionStrategy: modelSelectionInfo.selectionStrategy,
|
|
1094
1087
|
};
|
|
1095
1088
|
promptRun.ModelSelection = JSON.stringify(dbSelectionInfo);
|
|
1096
1089
|
promptRun.SelectionStrategy = modelSelectionInfo.selectionStrategy || 'Default';
|
|
@@ -1115,9 +1108,7 @@ class AIPromptRunner {
|
|
|
1115
1108
|
promptRun.VendorID = modelWithVendor._selectedVendorId;
|
|
1116
1109
|
}
|
|
1117
1110
|
else {
|
|
1118
|
-
const modelVendors = aiengine_1.AIEngine.Instance.ModelVendors
|
|
1119
|
-
.filter((mv) => mv.ModelID === model.ID && mv.Status === 'Active' && this.isInferenceProvider(mv))
|
|
1120
|
-
.sort((a, b) => b.Priority - a.Priority);
|
|
1111
|
+
const modelVendors = aiengine_1.AIEngine.Instance.ModelVendors.filter((mv) => mv.ModelID === model.ID && mv.Status === 'Active' && this.isInferenceProvider(mv)).sort((a, b) => b.Priority - a.Priority);
|
|
1121
1112
|
if (modelVendors.length > 0) {
|
|
1122
1113
|
promptRun.VendorID = modelVendors[0].VendorID;
|
|
1123
1114
|
}
|
|
@@ -1199,9 +1190,9 @@ class AIPromptRunner {
|
|
|
1199
1190
|
if (systemPromptText) {
|
|
1200
1191
|
messages.push({
|
|
1201
1192
|
role: 'system',
|
|
1202
|
-
content: systemPromptText
|
|
1193
|
+
content: systemPromptText,
|
|
1203
1194
|
});
|
|
1204
|
-
messages.push(...params.conversationMessages || []);
|
|
1195
|
+
messages.push(...(params.conversationMessages || []));
|
|
1205
1196
|
}
|
|
1206
1197
|
promptRun.Messages = JSON.stringify({
|
|
1207
1198
|
data: params.data,
|
|
@@ -1224,9 +1215,9 @@ class AIPromptRunner {
|
|
|
1224
1215
|
metadata: {
|
|
1225
1216
|
promptId: prompt.ID,
|
|
1226
1217
|
modelId: model.ID,
|
|
1227
|
-
vendorId
|
|
1218
|
+
vendorId,
|
|
1228
1219
|
},
|
|
1229
|
-
maxErrorLength: params.maxErrorLength
|
|
1220
|
+
maxErrorLength: params.maxErrorLength,
|
|
1230
1221
|
});
|
|
1231
1222
|
throw new Error(error);
|
|
1232
1223
|
}
|
|
@@ -1235,7 +1226,7 @@ class AIPromptRunner {
|
|
|
1235
1226
|
await params.onPromptRunCreated(promptRun.ID);
|
|
1236
1227
|
}
|
|
1237
1228
|
catch (callbackError) {
|
|
1238
|
-
(0,
|
|
1229
|
+
(0, global_1.LogStatus)(`Error in onPromptRunCreated callback: ${callbackError.message}`);
|
|
1239
1230
|
}
|
|
1240
1231
|
}
|
|
1241
1232
|
return promptRun;
|
|
@@ -1246,9 +1237,9 @@ class AIPromptRunner {
|
|
|
1246
1237
|
category: 'PromptRunSave',
|
|
1247
1238
|
metadata: {
|
|
1248
1239
|
promptRunId: promptRun.ID,
|
|
1249
|
-
saveError: promptRun.LatestResult?.Message
|
|
1240
|
+
saveError: promptRun.LatestResult?.Message,
|
|
1250
1241
|
},
|
|
1251
|
-
maxErrorLength: params.maxErrorLength
|
|
1242
|
+
maxErrorLength: params.maxErrorLength,
|
|
1252
1243
|
});
|
|
1253
1244
|
throw new Error(msg);
|
|
1254
1245
|
}
|
|
@@ -1263,7 +1254,7 @@ class AIPromptRunner {
|
|
|
1263
1254
|
const mergedData = {
|
|
1264
1255
|
...systemPlaceholders,
|
|
1265
1256
|
...params.data,
|
|
1266
|
-
...params.templateData
|
|
1257
|
+
...params.templateData,
|
|
1267
1258
|
};
|
|
1268
1259
|
return await this._templateEngine.RenderTemplate(template, templateContent, mergedData);
|
|
1269
1260
|
}
|
|
@@ -1273,9 +1264,9 @@ class AIPromptRunner {
|
|
|
1273
1264
|
metadata: {
|
|
1274
1265
|
templateId: template.ID,
|
|
1275
1266
|
templateName: template.Name,
|
|
1276
|
-
hasChildPrompts: !!params.childPrompts?.length
|
|
1267
|
+
hasChildPrompts: !!params.childPrompts?.length,
|
|
1277
1268
|
},
|
|
1278
|
-
maxErrorLength: params.maxErrorLength
|
|
1269
|
+
maxErrorLength: params.maxErrorLength,
|
|
1279
1270
|
});
|
|
1280
1271
|
throw error;
|
|
1281
1272
|
}
|
|
@@ -1299,17 +1290,19 @@ class AIPromptRunner {
|
|
|
1299
1290
|
try {
|
|
1300
1291
|
if (attemptNumber > 1) {
|
|
1301
1292
|
const vendorName = currentVendorId
|
|
1302
|
-
? aiengine_1.AIEngine.Instance.Vendors.find(v => v.ID === currentVendorId)?.Name || 'Unknown'
|
|
1293
|
+
? aiengine_1.AIEngine.Instance.Vendors.find((v) => v.ID === currentVendorId)?.Name || 'Unknown'
|
|
1303
1294
|
: 'default';
|
|
1304
|
-
(0,
|
|
1295
|
+
(0, global_1.LogStatusEx)({
|
|
1305
1296
|
message: `🔄 Failover attempt ${attemptNumber} with model ${currentModel.Name} (vendor: ${currentVendorId || 'default'})`,
|
|
1306
1297
|
category: 'AI',
|
|
1307
|
-
additionalArgs: [
|
|
1298
|
+
additionalArgs: [
|
|
1299
|
+
{
|
|
1308
1300
|
promptId: prompt.ID,
|
|
1309
1301
|
modelId: currentModel.ID,
|
|
1310
1302
|
vendorId: currentVendorId,
|
|
1311
|
-
attemptNumber
|
|
1312
|
-
}
|
|
1303
|
+
attemptNumber,
|
|
1304
|
+
},
|
|
1305
|
+
],
|
|
1313
1306
|
});
|
|
1314
1307
|
}
|
|
1315
1308
|
const result = await this.executeModel(currentModel, renderedPrompt, prompt, params, currentVendorId, conversationMessages, templateMessageRole, cancellationToken, vendorDriverClass, vendorApiName, vendorSupportsEffortLevel);
|
|
@@ -1329,7 +1322,7 @@ class AIPromptRunner {
|
|
|
1329
1322
|
error: lastError,
|
|
1330
1323
|
errorType: errorAnalysis.errorType,
|
|
1331
1324
|
duration: attemptDuration,
|
|
1332
|
-
timestamp: new Date()
|
|
1325
|
+
timestamp: new Date(),
|
|
1333
1326
|
};
|
|
1334
1327
|
failoverAttempts.push(failoverAttempt);
|
|
1335
1328
|
allCandidates = this.filterAuthenticationFailedVendor(errorAnalysis.errorType, currentVendorId, allCandidates);
|
|
@@ -1362,11 +1355,11 @@ class AIPromptRunner {
|
|
|
1362
1355
|
const aiEngine = aiengine_1.AIEngine.Instance;
|
|
1363
1356
|
let allModels;
|
|
1364
1357
|
if (prompt.AIModelTypeID) {
|
|
1365
|
-
const modelType = aiEngine.ModelTypes.find(mt => mt.ID === prompt.AIModelTypeID);
|
|
1358
|
+
const modelType = aiEngine.ModelTypes.find((mt) => mt.ID === prompt.AIModelTypeID);
|
|
1366
1359
|
if (!modelType) {
|
|
1367
1360
|
throw new Error(`Model type ${prompt.AIModelTypeID} not found`);
|
|
1368
1361
|
}
|
|
1369
|
-
allModels = aiEngine.Models.filter(m => m.AIModelType?.trim().toLowerCase() === modelType.Name.trim().toLowerCase());
|
|
1362
|
+
allModels = aiEngine.Models.filter((m) => m.AIModelType?.trim().toLowerCase() === modelType.Name.trim().toLowerCase());
|
|
1370
1363
|
}
|
|
1371
1364
|
else {
|
|
1372
1365
|
allModels = aiEngine.Models;
|
|
@@ -1387,7 +1380,7 @@ class AIPromptRunner {
|
|
|
1387
1380
|
supportsEffortLevel: model.SupportsEffortLevel ?? false,
|
|
1388
1381
|
isPreferredVendor: false,
|
|
1389
1382
|
priority: model.PowerRank || 0,
|
|
1390
|
-
source: 'power-rank'
|
|
1383
|
+
source: 'power-rank',
|
|
1391
1384
|
});
|
|
1392
1385
|
}
|
|
1393
1386
|
else {
|
|
@@ -1401,7 +1394,7 @@ class AIPromptRunner {
|
|
|
1401
1394
|
supportsEffortLevel: vendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
1402
1395
|
isPreferredVendor: vendor.Priority > 0,
|
|
1403
1396
|
priority: (model.PowerRank || 0) + (vendor.Priority || 0),
|
|
1404
|
-
source: 'power-rank'
|
|
1397
|
+
source: 'power-rank',
|
|
1405
1398
|
});
|
|
1406
1399
|
}
|
|
1407
1400
|
}
|
|
@@ -1410,13 +1403,13 @@ class AIPromptRunner {
|
|
|
1410
1403
|
}
|
|
1411
1404
|
updatePromptRunWithFailoverSuccess(promptRun, failoverAttempts, currentModel, currentVendorId) {
|
|
1412
1405
|
promptRun.FailoverAttempts = failoverAttempts.length;
|
|
1413
|
-
promptRun.FailoverErrors = JSON.stringify(failoverAttempts.map(a => ({
|
|
1406
|
+
promptRun.FailoverErrors = JSON.stringify(failoverAttempts.map((a) => ({
|
|
1414
1407
|
model: a.modelId,
|
|
1415
1408
|
vendor: a.vendorId,
|
|
1416
1409
|
error: a.error.message,
|
|
1417
|
-
errorType: a.errorType
|
|
1410
|
+
errorType: a.errorType,
|
|
1418
1411
|
})));
|
|
1419
|
-
promptRun.FailoverDurations = JSON.stringify(failoverAttempts.map(a => a.duration));
|
|
1412
|
+
promptRun.FailoverDurations = JSON.stringify(failoverAttempts.map((a) => a.duration));
|
|
1420
1413
|
promptRun.TotalFailoverDuration = failoverAttempts.reduce((sum, a) => sum + a.duration, 0);
|
|
1421
1414
|
if (currentModel.ID !== promptRun.OriginalModelID) {
|
|
1422
1415
|
promptRun.ModelID = currentModel.ID;
|
|
@@ -1427,20 +1420,19 @@ class AIPromptRunner {
|
|
|
1427
1420
|
}
|
|
1428
1421
|
updatePromptRunWithFailoverFailure(promptRun, failoverAttempts) {
|
|
1429
1422
|
promptRun.FailoverAttempts = failoverAttempts.length;
|
|
1430
|
-
promptRun.FailoverErrors = JSON.stringify(failoverAttempts.map(a => ({
|
|
1423
|
+
promptRun.FailoverErrors = JSON.stringify(failoverAttempts.map((a) => ({
|
|
1431
1424
|
model: a.modelId,
|
|
1432
1425
|
vendor: a.vendorId,
|
|
1433
1426
|
error: a.error.message,
|
|
1434
|
-
errorType: a.errorType
|
|
1427
|
+
errorType: a.errorType,
|
|
1435
1428
|
})));
|
|
1436
|
-
promptRun.FailoverDurations = JSON.stringify(failoverAttempts.map(a => a.duration));
|
|
1429
|
+
promptRun.FailoverDurations = JSON.stringify(failoverAttempts.map((a) => a.duration));
|
|
1437
1430
|
promptRun.TotalFailoverDuration = failoverAttempts.reduce((sum, a) => sum + a.duration, 0);
|
|
1438
1431
|
}
|
|
1439
1432
|
createFailoverErrorResult(lastError, failoverAttempts) {
|
|
1440
1433
|
const startTime = new Date();
|
|
1441
1434
|
const endTime = new Date();
|
|
1442
|
-
const hasContextLengthError = failoverAttempts.some(a => a.errorType === 'ContextLengthExceeded' ||
|
|
1443
|
-
ai_1.ErrorAnalyzer.analyzeError(a.error).errorType === 'ContextLengthExceeded');
|
|
1435
|
+
const hasContextLengthError = failoverAttempts.some((a) => a.errorType === 'ContextLengthExceeded' || ai_1.ErrorAnalyzer.analyzeError(a.error).errorType === 'ContextLengthExceeded');
|
|
1444
1436
|
let errorInfo;
|
|
1445
1437
|
if (lastError) {
|
|
1446
1438
|
errorInfo = ai_1.ErrorAnalyzer.analyzeError(lastError);
|
|
@@ -1457,7 +1449,7 @@ class AIPromptRunner {
|
|
|
1457
1449
|
errorInfo: errorInfo,
|
|
1458
1450
|
statusText: `Failover failed after ${failoverAttempts.length} attempts`,
|
|
1459
1451
|
timeElapsed: endTime.getTime() - startTime.getTime(),
|
|
1460
|
-
data: null
|
|
1452
|
+
data: null,
|
|
1461
1453
|
};
|
|
1462
1454
|
}
|
|
1463
1455
|
async executeModel(model, renderedPrompt, prompt, params, vendorId, conversationMessages, templateMessageRole = 'system', cancellationToken, vendorDriverClass, vendorApiName, vendorSupportsEffortLevel) {
|
|
@@ -1466,7 +1458,7 @@ class AIPromptRunner {
|
|
|
1466
1458
|
let llm;
|
|
1467
1459
|
let chatParams;
|
|
1468
1460
|
try {
|
|
1469
|
-
const verbose = params.verbose === true || (0,
|
|
1461
|
+
const verbose = params.verbose === true || (0, global_1.IsVerboseLoggingEnabled)();
|
|
1470
1462
|
let supportsEffortLevel = false;
|
|
1471
1463
|
if (vendorDriverClass && vendorApiName) {
|
|
1472
1464
|
driverClass = vendorDriverClass;
|
|
@@ -1491,7 +1483,7 @@ class AIPromptRunner {
|
|
|
1491
1483
|
}
|
|
1492
1484
|
let apiKey;
|
|
1493
1485
|
if (params.apiKeys && params.apiKeys.length > 0) {
|
|
1494
|
-
const localKey = params.apiKeys.find(k => k.driverClass === driverClass);
|
|
1486
|
+
const localKey = params.apiKeys.find((k) => k.driverClass === driverClass);
|
|
1495
1487
|
if (localKey) {
|
|
1496
1488
|
apiKey = localKey.apiKey;
|
|
1497
1489
|
if (verbose) {
|
|
@@ -1508,7 +1500,7 @@ class AIPromptRunner {
|
|
|
1508
1500
|
else {
|
|
1509
1501
|
apiKey = (0, ai_1.GetAIAPIKey)(driverClass);
|
|
1510
1502
|
}
|
|
1511
|
-
llm =
|
|
1503
|
+
llm = global_2.MJGlobal.Instance.ClassFactory.CreateInstance(ai_1.BaseLLM, driverClass, apiKey);
|
|
1512
1504
|
chatParams = new ai_1.ChatParams();
|
|
1513
1505
|
if (!apiName) {
|
|
1514
1506
|
throw new Error(`No API name found for model ${model.Name}. Please ensure the model or its vendor configuration includes an APIName.`);
|
|
@@ -1530,7 +1522,9 @@ class AIPromptRunner {
|
|
|
1530
1522
|
if (prompt.Seed != null)
|
|
1531
1523
|
chatParams.seed = prompt.Seed;
|
|
1532
1524
|
if (prompt.StopSequences) {
|
|
1533
|
-
chatParams.stopSequences = prompt.StopSequences.split(',')
|
|
1525
|
+
chatParams.stopSequences = prompt.StopSequences.split(',')
|
|
1526
|
+
.map((s) => s.trim())
|
|
1527
|
+
.filter((s) => s.length > 0);
|
|
1534
1528
|
}
|
|
1535
1529
|
if (prompt.IncludeLogProbs != null)
|
|
1536
1530
|
chatParams.includeLogProbs = prompt.IncludeLogProbs;
|
|
@@ -1617,9 +1611,9 @@ class AIPromptRunner {
|
|
|
1617
1611
|
model: model,
|
|
1618
1612
|
metadata: {
|
|
1619
1613
|
vendorId,
|
|
1620
|
-
errorInfo
|
|
1614
|
+
errorInfo,
|
|
1621
1615
|
},
|
|
1622
|
-
maxErrorLength: params.maxErrorLength
|
|
1616
|
+
maxErrorLength: params.maxErrorLength,
|
|
1623
1617
|
});
|
|
1624
1618
|
throw error;
|
|
1625
1619
|
}
|
|
@@ -1664,7 +1658,7 @@ class AIPromptRunner {
|
|
|
1664
1658
|
throw new Error('Execution was cancelled during validation retries');
|
|
1665
1659
|
}
|
|
1666
1660
|
if (attempt > 0) {
|
|
1667
|
-
(0,
|
|
1661
|
+
(0, global_1.LogStatus)(` 🔄 Retrying execution due to validation failure, attempt ${attempt + 1}/${maxRetries + 1}`);
|
|
1668
1662
|
await this.applyRetryDelay(prompt, attempt);
|
|
1669
1663
|
}
|
|
1670
1664
|
const modelResult = await this.executeModelWithFailover(selectedModel, renderedPromptText, prompt, params, promptRun.VendorID, params.conversationMessages, params.templateMessageRole || 'system', params.cancellationToken, allCandidates, promptRun, vendorDriverClass, vendorApiName, vendorSupportsEffortLevel);
|
|
@@ -1681,7 +1675,7 @@ class AIPromptRunner {
|
|
|
1681
1675
|
modelResult,
|
|
1682
1676
|
parsedResult: {
|
|
1683
1677
|
result: null,
|
|
1684
|
-
validationResult: undefined
|
|
1678
|
+
validationResult: undefined,
|
|
1685
1679
|
},
|
|
1686
1680
|
validationAttempts,
|
|
1687
1681
|
cumulativeTokens: {
|
|
@@ -1700,7 +1694,7 @@ class AIPromptRunner {
|
|
|
1700
1694
|
const validationAttempt = {
|
|
1701
1695
|
attemptNumber: attempt + 1,
|
|
1702
1696
|
success: validationResult?.Success || false,
|
|
1703
|
-
errorMessage: validationErrors?.length ? validationErrors.map(e => e.Message).join('; ') : undefined,
|
|
1697
|
+
errorMessage: validationErrors?.length ? validationErrors.map((e) => e.Message).join('; ') : undefined,
|
|
1704
1698
|
validationErrors,
|
|
1705
1699
|
rawOutput: modelResult.data?.choices?.[0]?.message?.content || '',
|
|
1706
1700
|
parsedOutput: result,
|
|
@@ -1720,15 +1714,15 @@ class AIPromptRunner {
|
|
|
1720
1714
|
};
|
|
1721
1715
|
}
|
|
1722
1716
|
if (prompt.ValidationBehavior === 'Strict' && attempt < maxRetries) {
|
|
1723
|
-
lastError = new Error(`Validation failed: ${validationErrors?.map(e => e.Message).join('; ')}`);
|
|
1724
|
-
(0,
|
|
1717
|
+
lastError = new Error(`Validation failed: ${validationErrors?.map((e) => e.Message).join('; ')}`);
|
|
1718
|
+
(0, global_1.LogStatus)(` ⚠️ Validation failed on attempt ${attempt + 1}, will retry (Strict mode)`);
|
|
1725
1719
|
continue;
|
|
1726
1720
|
}
|
|
1727
1721
|
else {
|
|
1728
1722
|
const reason = prompt.ValidationBehavior !== 'Strict'
|
|
1729
1723
|
? `${prompt.ValidationBehavior || 'None'} mode - continuing with invalid output (no retry)`
|
|
1730
1724
|
: 'max retries exceeded';
|
|
1731
|
-
(0,
|
|
1725
|
+
(0, global_1.LogStatus)(` ⚠️ Validation failed on attempt ${attempt + 1}, stopping retries (${reason})`);
|
|
1732
1726
|
return {
|
|
1733
1727
|
modelResult,
|
|
1734
1728
|
parsedResult: { result, validationResult },
|
|
@@ -1749,9 +1743,9 @@ class AIPromptRunner {
|
|
|
1749
1743
|
metadata: {
|
|
1750
1744
|
attempt: attempt + 1,
|
|
1751
1745
|
maxRetries: maxRetries + 1,
|
|
1752
|
-
modelName: selectedModel.Name
|
|
1746
|
+
modelName: selectedModel.Name,
|
|
1753
1747
|
},
|
|
1754
|
-
maxErrorLength: params.maxErrorLength
|
|
1748
|
+
maxErrorLength: params.maxErrorLength,
|
|
1755
1749
|
});
|
|
1756
1750
|
const validationAttempt = {
|
|
1757
1751
|
attemptNumber: attempt + 1,
|
|
@@ -1792,8 +1786,8 @@ class AIPromptRunner {
|
|
|
1792
1786
|
async applyRetryDelay(prompt, attemptNumber, suggestedDelaySeconds) {
|
|
1793
1787
|
const delay = this.calculateRetryDelay(prompt, attemptNumber, suggestedDelaySeconds);
|
|
1794
1788
|
const delaySeconds = (delay / 1000).toFixed(1);
|
|
1795
|
-
(0,
|
|
1796
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
1789
|
+
(0, global_1.LogStatus)(` Waiting ${delaySeconds}s before retry (strategy: ${prompt.RetryStrategy || 'Fixed'})...`);
|
|
1790
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1797
1791
|
}
|
|
1798
1792
|
filterAuthenticationFailedVendor(errorType, currentVendorId, allCandidates) {
|
|
1799
1793
|
if (errorType !== 'Authentication') {
|
|
@@ -1801,10 +1795,10 @@ class AIPromptRunner {
|
|
|
1801
1795
|
}
|
|
1802
1796
|
const failedVendorId = currentVendorId || 'default';
|
|
1803
1797
|
const beforeCount = allCandidates.length;
|
|
1804
|
-
const filteredCandidates = allCandidates.filter(c => (c.vendorId || 'default') !== failedVendorId);
|
|
1798
|
+
const filteredCandidates = allCandidates.filter((c) => (c.vendorId || 'default') !== failedVendorId);
|
|
1805
1799
|
const removedCount = beforeCount - filteredCandidates.length;
|
|
1806
1800
|
if (removedCount > 0) {
|
|
1807
|
-
const vendorName = aiengine_1.AIEngine.Instance.Vendors.find(v => v.ID === failedVendorId)?.Name || failedVendorId;
|
|
1801
|
+
const vendorName = aiengine_1.AIEngine.Instance.Vendors.find((v) => v.ID === failedVendorId)?.Name || failedVendorId;
|
|
1808
1802
|
const remainingCount = filteredCandidates.length;
|
|
1809
1803
|
this.logStatus(` 🔒 Invalid API key for ${vendorName} - excluding ${removedCount} model${removedCount === 1 ? '' : 's'} from this vendor (${remainingCount} remaining)`, true);
|
|
1810
1804
|
}
|
|
@@ -1815,16 +1809,12 @@ class AIPromptRunner {
|
|
|
1815
1809
|
if (!isRateLimit) {
|
|
1816
1810
|
return false;
|
|
1817
1811
|
}
|
|
1818
|
-
const rateLimitRetryCount = failoverAttempts.filter(a => a.modelId === currentModel.ID &&
|
|
1819
|
-
a.vendorId === currentVendorId &&
|
|
1820
|
-
a.errorType === 'RateLimit').length;
|
|
1812
|
+
const rateLimitRetryCount = failoverAttempts.filter((a) => a.modelId === currentModel.ID && a.vendorId === currentVendorId && a.errorType === 'RateLimit').length;
|
|
1821
1813
|
const maxRetries = prompt.MaxRetries ?? 3;
|
|
1822
1814
|
const shouldRetry = rateLimitRetryCount <= maxRetries;
|
|
1823
1815
|
if (shouldRetry) {
|
|
1824
1816
|
const modelName = currentModel.Name;
|
|
1825
|
-
const vendorName = currentVendorId
|
|
1826
|
-
? aiengine_1.AIEngine.Instance.Vendors.find(v => v.ID === currentVendorId)?.Name || 'default'
|
|
1827
|
-
: 'default';
|
|
1817
|
+
const vendorName = currentVendorId ? aiengine_1.AIEngine.Instance.Vendors.find((v) => v.ID === currentVendorId)?.Name || 'default' : 'default';
|
|
1828
1818
|
this.logStatus(` ⏳ Rate limit hit - retrying ${modelName} (${vendorName}) with backoff (attempt ${rateLimitRetryCount}/${maxRetries})`, true);
|
|
1829
1819
|
this.logFailoverAttempt(prompt.ID, failoverAttempt, true);
|
|
1830
1820
|
if (attemptNumber < maxAttempts) {
|
|
@@ -1844,21 +1834,19 @@ class AIPromptRunner {
|
|
|
1844
1834
|
this.logFailoverAttempt(promptId, failoverAttempt, true);
|
|
1845
1835
|
if (attemptNumber < failoverConfig.maxAttempts) {
|
|
1846
1836
|
const delay = this.calculateFailoverDelay(attemptNumber, failoverConfig.delaySeconds);
|
|
1847
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
1837
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1848
1838
|
}
|
|
1849
1839
|
return {
|
|
1850
1840
|
model: nextCandidate.model,
|
|
1851
1841
|
vendorId: nextCandidate.vendorId,
|
|
1852
1842
|
driverClass: nextCandidate.driverClass,
|
|
1853
1843
|
apiName: nextCandidate.apiName,
|
|
1854
|
-
supportsEffortLevel: nextCandidate.supportsEffortLevel || false
|
|
1844
|
+
supportsEffortLevel: nextCandidate.supportsEffortLevel || false,
|
|
1855
1845
|
};
|
|
1856
1846
|
}
|
|
1857
1847
|
getValidationDecisionDescription(finalSuccess, totalAttempts, validationBehavior) {
|
|
1858
1848
|
if (finalSuccess) {
|
|
1859
|
-
return totalAttempts === 1
|
|
1860
|
-
? 'Validation passed on first attempt'
|
|
1861
|
-
: `Validation passed after ${totalAttempts} attempts`;
|
|
1849
|
+
return totalAttempts === 1 ? 'Validation passed on first attempt' : `Validation passed after ${totalAttempts} attempts`;
|
|
1862
1850
|
}
|
|
1863
1851
|
else {
|
|
1864
1852
|
switch (validationBehavior) {
|
|
@@ -1987,9 +1975,9 @@ class AIPromptRunner {
|
|
|
1987
1975
|
}
|
|
1988
1976
|
}
|
|
1989
1977
|
catch (parseError) {
|
|
1990
|
-
const validationResult = new
|
|
1978
|
+
const validationResult = new global_2.ValidationResult();
|
|
1991
1979
|
validationResult.Success = false;
|
|
1992
|
-
const error = new
|
|
1980
|
+
const error = new global_2.ValidationErrorInfo('parseAndValidateResultEnhanced', `Invalid OutputExample JSON: ${parseError.message}`, rawOutput, global_2.ValidationErrorType.Failure);
|
|
1993
1981
|
validationErrors.push(error);
|
|
1994
1982
|
validationResult.Errors = validationErrors;
|
|
1995
1983
|
return { result: rawOutput, validationResult, validationErrors };
|
|
@@ -2000,11 +1988,11 @@ class AIPromptRunner {
|
|
|
2000
1988
|
validationErrors.push(...schemaValidationErrors);
|
|
2001
1989
|
}
|
|
2002
1990
|
catch (schemaError) {
|
|
2003
|
-
const error = new
|
|
1991
|
+
const error = new global_2.ValidationErrorInfo('schema', `Schema validation failed: ${schemaError.message}`, undefined, global_2.ValidationErrorType.Failure);
|
|
2004
1992
|
validationErrors.push(error);
|
|
2005
1993
|
}
|
|
2006
1994
|
}
|
|
2007
|
-
const validationResult = new
|
|
1995
|
+
const validationResult = new global_2.ValidationResult();
|
|
2008
1996
|
validationResult.Success = validationErrors.length === 0;
|
|
2009
1997
|
validationResult.Errors = validationErrors;
|
|
2010
1998
|
return { result: parsedResult, validationResult, validationErrors };
|
|
@@ -2015,15 +2003,16 @@ class AIPromptRunner {
|
|
|
2015
2003
|
metadata: {
|
|
2016
2004
|
rawOutput: rawOutput?.substring(0, 200),
|
|
2017
2005
|
outputType: prompt.OutputType,
|
|
2018
|
-
parseAttempt: true
|
|
2006
|
+
parseAttempt: true,
|
|
2019
2007
|
},
|
|
2020
|
-
maxErrorLength: params?.maxErrorLength
|
|
2008
|
+
maxErrorLength: params?.maxErrorLength,
|
|
2021
2009
|
});
|
|
2022
|
-
const validationResult = new
|
|
2010
|
+
const validationResult = new global_2.ValidationResult();
|
|
2023
2011
|
validationResult.Success = false;
|
|
2024
|
-
validationResult.Errors =
|
|
2025
|
-
|
|
2026
|
-
|
|
2012
|
+
validationResult.Errors =
|
|
2013
|
+
validationErrors.length > 0
|
|
2014
|
+
? validationErrors
|
|
2015
|
+
: [new global_2.ValidationErrorInfo('general', error.message, undefined, global_2.ValidationErrorType.Failure)];
|
|
2027
2016
|
switch (prompt.ValidationBehavior) {
|
|
2028
2017
|
case 'Strict':
|
|
2029
2018
|
return { result: undefined, validationResult, validationErrors: validationResult.Errors };
|
|
@@ -2034,9 +2023,9 @@ class AIPromptRunner {
|
|
|
2034
2023
|
prompt: prompt,
|
|
2035
2024
|
metadata: {
|
|
2036
2025
|
validationPath: error.dataPath,
|
|
2037
|
-
validationMessage: error.message
|
|
2026
|
+
validationMessage: error.message,
|
|
2038
2027
|
},
|
|
2039
|
-
maxErrorLength: params?.maxErrorLength
|
|
2028
|
+
maxErrorLength: params?.maxErrorLength,
|
|
2040
2029
|
});
|
|
2041
2030
|
return { result: modelResult.data?.choices?.[0]?.message?.content, validationResult, validationErrors: validationResult.Errors };
|
|
2042
2031
|
case 'None':
|
|
@@ -2053,7 +2042,7 @@ class AIPromptRunner {
|
|
|
2053
2042
|
const numberResult = parseFloat(rawOutput);
|
|
2054
2043
|
if (isNaN(numberResult)) {
|
|
2055
2044
|
if (!skipValidation) {
|
|
2056
|
-
const error = new
|
|
2045
|
+
const error = new global_2.ValidationErrorInfo('output', `Expected number output but got: ${rawOutput}`, rawOutput, global_2.ValidationErrorType.Failure);
|
|
2057
2046
|
validationErrors.push(error);
|
|
2058
2047
|
throw new Error(error.Message);
|
|
2059
2048
|
}
|
|
@@ -2070,7 +2059,7 @@ class AIPromptRunner {
|
|
|
2070
2059
|
return false;
|
|
2071
2060
|
}
|
|
2072
2061
|
else if (!skipValidation) {
|
|
2073
|
-
const error = new
|
|
2062
|
+
const error = new global_2.ValidationErrorInfo('output', `Expected boolean output but got: ${rawOutput}`, rawOutput, global_2.ValidationErrorType.Failure);
|
|
2074
2063
|
validationErrors.push(error);
|
|
2075
2064
|
throw new Error(error.Message);
|
|
2076
2065
|
}
|
|
@@ -2079,7 +2068,7 @@ class AIPromptRunner {
|
|
|
2079
2068
|
parseDateOutput(rawOutput, skipValidation, validationErrors) {
|
|
2080
2069
|
const dateResult = new Date(rawOutput);
|
|
2081
2070
|
if (isNaN(dateResult.getTime()) && !skipValidation) {
|
|
2082
|
-
const error = new
|
|
2071
|
+
const error = new global_2.ValidationErrorInfo('output', `Expected date output but got: ${rawOutput}`, rawOutput, global_2.ValidationErrorType.Failure);
|
|
2083
2072
|
validationErrors.push(error);
|
|
2084
2073
|
throw new Error(error.Message);
|
|
2085
2074
|
}
|
|
@@ -2088,7 +2077,7 @@ class AIPromptRunner {
|
|
|
2088
2077
|
async parseObjectOutput(rawOutput, prompt, skipValidation, cleanValidationSyntax, validationErrors, currentPromptRun, params) {
|
|
2089
2078
|
let parsedResult;
|
|
2090
2079
|
try {
|
|
2091
|
-
parsedResult = JSON.parse((0,
|
|
2080
|
+
parsedResult = JSON.parse((0, global_2.CleanJSON)(rawOutput));
|
|
2092
2081
|
}
|
|
2093
2082
|
catch (jsonError) {
|
|
2094
2083
|
if (params?.attemptJSONRepair && prompt.OutputType === 'object') {
|
|
@@ -2096,7 +2085,7 @@ class AIPromptRunner {
|
|
|
2096
2085
|
}
|
|
2097
2086
|
else {
|
|
2098
2087
|
if (!skipValidation) {
|
|
2099
|
-
const error = new
|
|
2088
|
+
const error = new global_2.ValidationErrorInfo('output', `Expected JSON object but got invalid JSON: ${rawOutput}`, rawOutput, global_2.ValidationErrorType.Failure);
|
|
2100
2089
|
validationErrors.push(error);
|
|
2101
2090
|
throw new Error(error.Message);
|
|
2102
2091
|
}
|
|
@@ -2104,7 +2093,7 @@ class AIPromptRunner {
|
|
|
2104
2093
|
}
|
|
2105
2094
|
}
|
|
2106
2095
|
if (parsedResult && (cleanValidationSyntax || (!skipValidation && prompt.OutputExample))) {
|
|
2107
|
-
const validator = new
|
|
2096
|
+
const validator = new global_2.JSONValidator();
|
|
2108
2097
|
parsedResult = validator.cleanValidationSyntax(parsedResult);
|
|
2109
2098
|
}
|
|
2110
2099
|
return parsedResult;
|
|
@@ -2115,9 +2104,9 @@ class AIPromptRunner {
|
|
|
2115
2104
|
category: 'JSONRepairSkipped',
|
|
2116
2105
|
metadata: {
|
|
2117
2106
|
originalError: originalError.message,
|
|
2118
|
-
rawOutput: rawOutput.substring(0, 500)
|
|
2107
|
+
rawOutput: rawOutput.substring(0, 500),
|
|
2119
2108
|
},
|
|
2120
|
-
maxErrorLength: params.maxErrorLength
|
|
2109
|
+
maxErrorLength: params.maxErrorLength,
|
|
2121
2110
|
});
|
|
2122
2111
|
throw new Error(`JSON repair skipped: raw output does not contain JSON-like characters. Original error: ${originalError.message}`);
|
|
2123
2112
|
}
|
|
@@ -2125,16 +2114,16 @@ class AIPromptRunner {
|
|
|
2125
2114
|
this.logStatus(' 🔧 Attempting JSON repair with JSON5...', true, params);
|
|
2126
2115
|
let jsonToParse = rawOutput;
|
|
2127
2116
|
try {
|
|
2128
|
-
jsonToParse = (0,
|
|
2117
|
+
jsonToParse = (0, global_2.CleanJSON)(rawOutput);
|
|
2129
2118
|
}
|
|
2130
2119
|
catch (cleanError) {
|
|
2131
2120
|
this.logError(cleanError, {
|
|
2132
2121
|
category: 'JSONCleaningFailed',
|
|
2133
2122
|
metadata: {
|
|
2134
2123
|
originalError: originalError.message,
|
|
2135
|
-
rawOutput: rawOutput.substring(0, 500)
|
|
2124
|
+
rawOutput: rawOutput.substring(0, 500),
|
|
2136
2125
|
},
|
|
2137
|
-
maxErrorLength: params.maxErrorLength
|
|
2126
|
+
maxErrorLength: params.maxErrorLength,
|
|
2138
2127
|
});
|
|
2139
2128
|
}
|
|
2140
2129
|
const json5Result = JSON5.parse(jsonToParse);
|
|
@@ -2144,7 +2133,7 @@ class AIPromptRunner {
|
|
|
2144
2133
|
catch (json5Error) {
|
|
2145
2134
|
this.logStatus(' 🤖 JSON5 failed, attempting AI-based JSON repair...', true, params);
|
|
2146
2135
|
try {
|
|
2147
|
-
const repairPrompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name.trim().toLowerCase() === 'repair json' && p.Category.trim().toLowerCase() === 'mj: system');
|
|
2136
|
+
const repairPrompt = aiengine_1.AIEngine.Instance.Prompts.find((p) => p.Name.trim().toLowerCase() === 'repair json' && p.Category.trim().toLowerCase() === 'mj: system');
|
|
2148
2137
|
if (!repairPrompt) {
|
|
2149
2138
|
throw new Error('Repair JSON prompt not found in MJ: System category');
|
|
2150
2139
|
}
|
|
@@ -2155,15 +2144,18 @@ class AIPromptRunner {
|
|
|
2155
2144
|
prompt: repairPrompt,
|
|
2156
2145
|
data: {
|
|
2157
2146
|
ERROR_MESSAGE: originalError.message,
|
|
2158
|
-
MALFORMED_JSON: rawOutput
|
|
2147
|
+
MALFORMED_JSON: rawOutput,
|
|
2159
2148
|
},
|
|
2160
|
-
skipValidation: true
|
|
2149
|
+
skipValidation: true,
|
|
2161
2150
|
});
|
|
2162
2151
|
if (!repairResult.success || !repairResult.result) {
|
|
2163
2152
|
throw new Error('AI-based JSON repair failed' + (repairResult.errorMessage ? `: ${repairResult.errorMessage}` : ''));
|
|
2164
2153
|
}
|
|
2165
2154
|
const repairedJSON = JSON.parse(repairResult.result);
|
|
2166
|
-
if (repairedJSON &&
|
|
2155
|
+
if (repairedJSON &&
|
|
2156
|
+
typeof repairedJSON === 'object' &&
|
|
2157
|
+
Object.keys(repairedJSON).length === 1 &&
|
|
2158
|
+
repairedJSON.error?.trim().toLowerCase() === 'not_json') {
|
|
2167
2159
|
throw new Error('AI-based JSON repair returned a non-JSON response indicating it could not repair the JSON');
|
|
2168
2160
|
}
|
|
2169
2161
|
this.logStatus(' ✅ AI successfully repaired the JSON', true, params);
|
|
@@ -2176,9 +2168,9 @@ class AIPromptRunner {
|
|
|
2176
2168
|
originalError: originalError.message,
|
|
2177
2169
|
json5Error: json5Error.message,
|
|
2178
2170
|
aiError: aiRepairError.message,
|
|
2179
|
-
rawOutput: rawOutput.substring(0, 500)
|
|
2171
|
+
rawOutput: rawOutput.substring(0, 500),
|
|
2180
2172
|
},
|
|
2181
|
-
maxErrorLength: params.maxErrorLength
|
|
2173
|
+
maxErrorLength: params.maxErrorLength,
|
|
2182
2174
|
});
|
|
2183
2175
|
throw new Error(`JSON repair failed after both JSON5 and AI attempts: ${originalError.message}`);
|
|
2184
2176
|
}
|
|
@@ -2192,26 +2184,26 @@ class AIPromptRunner {
|
|
|
2192
2184
|
exampleObject = JSON.parse(outputExample);
|
|
2193
2185
|
}
|
|
2194
2186
|
catch (parseError) {
|
|
2195
|
-
const error = new
|
|
2187
|
+
const error = new global_2.ValidationErrorInfo('outputExample', `Invalid OutputExample JSON: ${parseError.message}`, outputExample, global_2.ValidationErrorType.Failure);
|
|
2196
2188
|
validationErrors.push(error);
|
|
2197
2189
|
return validationErrors;
|
|
2198
2190
|
}
|
|
2199
2191
|
const validationResult = this._jsonValidator.validate(parsedResult, exampleObject);
|
|
2200
2192
|
validationErrors.push(...validationResult.Errors);
|
|
2201
2193
|
if (validationErrors.length !== 0) {
|
|
2202
|
-
(0,
|
|
2194
|
+
(0, global_1.LogStatus)(`⚠️ Validation found ${validationErrors.length} issues for prompt ${promptId}:`);
|
|
2203
2195
|
validationErrors.forEach((error, index) => {
|
|
2204
|
-
(0,
|
|
2196
|
+
(0, global_1.LogStatus)(` ${index + 1}. ${error.Source}: ${error.Message}`);
|
|
2205
2197
|
});
|
|
2206
|
-
(0,
|
|
2207
|
-
(0,
|
|
2208
|
-
(0,
|
|
2209
|
-
(0,
|
|
2210
|
-
(0,
|
|
2198
|
+
(0, global_1.LogStatus)(` Note: Validation syntax in OutputExample:`);
|
|
2199
|
+
(0, global_1.LogStatus)(` - '?' = optional field (e.g., "reasoning?": "...")`);
|
|
2200
|
+
(0, global_1.LogStatus)(` - '*' = required but any content (e.g., "payload*": {})`);
|
|
2201
|
+
(0, global_1.LogStatus)(` - ':type' = type validation (e.g., "age:number": 25)`);
|
|
2202
|
+
(0, global_1.LogStatus)(` - ':[N+]' = array length (e.g., "items:[2+]": [])`);
|
|
2211
2203
|
}
|
|
2212
2204
|
}
|
|
2213
2205
|
catch (error) {
|
|
2214
|
-
const validationError = new
|
|
2206
|
+
const validationError = new global_2.ValidationErrorInfo('validation', `Unexpected validation error: ${error.message}`, undefined, global_2.ValidationErrorType.Failure);
|
|
2215
2207
|
validationErrors.push(validationError);
|
|
2216
2208
|
}
|
|
2217
2209
|
return validationErrors;
|
|
@@ -2229,7 +2221,7 @@ class AIPromptRunner {
|
|
|
2229
2221
|
if (!promptRun.ErrorMessage) {
|
|
2230
2222
|
const validationErrors = parsedResult.validationResult?.Errors;
|
|
2231
2223
|
if (validationErrors && validationErrors.length > 0) {
|
|
2232
|
-
promptRun.ErrorMessage = `JSON parsing/validation failed: ${validationErrors.map(e => e.Message).join('; ')}`;
|
|
2224
|
+
promptRun.ErrorMessage = `JSON parsing/validation failed: ${validationErrors.map((e) => e.Message).join('; ')}`;
|
|
2233
2225
|
}
|
|
2234
2226
|
else {
|
|
2235
2227
|
promptRun.ErrorMessage = 'Failed to parse result into expected format; raw output saved instead';
|
|
@@ -2277,7 +2269,7 @@ class AIPromptRunner {
|
|
|
2277
2269
|
}
|
|
2278
2270
|
if (validationAttempts && validationAttempts.length > 0) {
|
|
2279
2271
|
promptRun.ValidationAttemptCount = validationAttempts.length;
|
|
2280
|
-
promptRun.SuccessfulValidationCount = validationAttempts.filter(a => a.success).length;
|
|
2272
|
+
promptRun.SuccessfulValidationCount = validationAttempts.filter((a) => a.success).length;
|
|
2281
2273
|
promptRun.FinalValidationPassed = parsedResult.validationResult?.Success === true;
|
|
2282
2274
|
promptRun.LastAttemptAt = endTime;
|
|
2283
2275
|
if (validationAttempts.length > 1) {
|
|
@@ -2293,9 +2285,9 @@ class AIPromptRunner {
|
|
|
2293
2285
|
promptRun.FinalValidationError = finalAttempt.errorMessage.substring(0, 500);
|
|
2294
2286
|
promptRun.ValidationErrorCount = finalAttempt.validationErrors?.length || 0;
|
|
2295
2287
|
}
|
|
2296
|
-
if (validationAttempts.some(a => !a.success)) {
|
|
2288
|
+
if (validationAttempts.some((a) => !a.success)) {
|
|
2297
2289
|
const errorCounts = new Map();
|
|
2298
|
-
validationAttempts.forEach(attempt => {
|
|
2290
|
+
validationAttempts.forEach((attempt) => {
|
|
2299
2291
|
if (!attempt.success && attempt.errorMessage) {
|
|
2300
2292
|
const count = errorCounts.get(attempt.errorMessage) || 0;
|
|
2301
2293
|
errorCounts.set(attempt.errorMessage, count + 1);
|
|
@@ -2306,17 +2298,17 @@ class AIPromptRunner {
|
|
|
2306
2298
|
promptRun.CommonValidationError = commonError.substring(0, 255);
|
|
2307
2299
|
}
|
|
2308
2300
|
}
|
|
2309
|
-
promptRun.ValidationAttempts = JSON.stringify(validationAttempts.map(a => ({
|
|
2301
|
+
promptRun.ValidationAttempts = JSON.stringify(validationAttempts.map((a) => ({
|
|
2310
2302
|
attemptNumber: a.attemptNumber,
|
|
2311
2303
|
success: a.success,
|
|
2312
2304
|
errorMessage: a.errorMessage,
|
|
2313
2305
|
validationErrorCount: a.validationErrors?.length || 0,
|
|
2314
2306
|
timestamp: a.timestamp.toISOString(),
|
|
2315
|
-
outputLength: a.rawOutput?.length || 0
|
|
2307
|
+
outputLength: a.rawOutput?.length || 0,
|
|
2316
2308
|
})));
|
|
2317
2309
|
promptRun.ValidationSummary = JSON.stringify({
|
|
2318
2310
|
totalAttempts: validationAttempts.length,
|
|
2319
|
-
successfulAttempts: validationAttempts.filter(a => a.success).length,
|
|
2311
|
+
successfulAttempts: validationAttempts.filter((a) => a.success).length,
|
|
2320
2312
|
finalSuccess: parsedResult.validationResult?.Success || false,
|
|
2321
2313
|
validationBehavior: promptRun.ValidationBehavior,
|
|
2322
2314
|
retryStrategy: promptRun.RetryStrategy,
|
|
@@ -2325,15 +2317,15 @@ class AIPromptRunner {
|
|
|
2325
2317
|
totalDurationMS: executionTimeMS,
|
|
2326
2318
|
retryDurationMS: promptRun.TotalRetryDurationMS || 0,
|
|
2327
2319
|
outputType: prompt.OutputType || 'unknown',
|
|
2328
|
-
hasOutputExample: !!
|
|
2320
|
+
hasOutputExample: !!prompt.OutputExample,
|
|
2329
2321
|
schemaValidationUsed: !!(prompt.OutputExample && prompt.OutputType === 'object'),
|
|
2330
|
-
finalValidationErrors: parsedResult.validationResult?.Errors?.map(e => ({
|
|
2322
|
+
finalValidationErrors: parsedResult.validationResult?.Errors?.map((e) => ({
|
|
2331
2323
|
source: e.Source,
|
|
2332
2324
|
message: e.Message,
|
|
2333
2325
|
type: e.Type,
|
|
2334
|
-
value: e.Value
|
|
2326
|
+
value: e.Value,
|
|
2335
2327
|
})) || [],
|
|
2336
|
-
validationDecision: this.getValidationDecisionDescription(parsedResult.validationResult?.Success || false, validationAttempts.length, promptRun.ValidationBehavior || 'Warn')
|
|
2328
|
+
validationDecision: this.getValidationDecisionDescription(parsedResult.validationResult?.Success || false, validationAttempts.length, promptRun.ValidationBehavior || 'Warn'),
|
|
2337
2329
|
});
|
|
2338
2330
|
}
|
|
2339
2331
|
else {
|
|
@@ -2343,14 +2335,14 @@ class AIPromptRunner {
|
|
|
2343
2335
|
promptRun.LastAttemptAt = endTime;
|
|
2344
2336
|
promptRun.TotalRetryDurationMS = 0;
|
|
2345
2337
|
}
|
|
2346
|
-
promptRun.Success = modelResult.success &&
|
|
2338
|
+
promptRun.Success = modelResult.success && parsedResult.validationResult?.Success !== false;
|
|
2347
2339
|
promptRun.Status = promptRun.Success ? 'Completed' : 'Failed';
|
|
2348
2340
|
if (!promptRun.Success) {
|
|
2349
2341
|
if (!modelResult.success && modelResult.errorMessage) {
|
|
2350
2342
|
promptRun.ErrorDetails = modelResult.errorMessage;
|
|
2351
2343
|
}
|
|
2352
2344
|
else if (parsedResult.validationResult?.Success === false) {
|
|
2353
|
-
promptRun.ErrorDetails = `Validation failed: ${parsedResult.validationResult.Errors?.map(e => e.Message).join(', ')}`;
|
|
2345
|
+
promptRun.ErrorDetails = `Validation failed: ${parsedResult.validationResult.Errors?.map((e) => e.Message).join(', ')}`;
|
|
2354
2346
|
}
|
|
2355
2347
|
}
|
|
2356
2348
|
promptRun.TokensPromptRollup = promptRun.TokensPrompt;
|
|
@@ -2364,9 +2356,8 @@ class AIPromptRunner {
|
|
|
2364
2356
|
let errorMsg = 'Unknown error';
|
|
2365
2357
|
try {
|
|
2366
2358
|
if (promptRun.LatestResult?.Message) {
|
|
2367
|
-
errorMsg =
|
|
2368
|
-
? promptRun.LatestResult.Message
|
|
2369
|
-
: String(promptRun.LatestResult.Message);
|
|
2359
|
+
errorMsg =
|
|
2360
|
+
typeof promptRun.LatestResult.Message === 'string' ? promptRun.LatestResult.Message : String(promptRun.LatestResult.Message);
|
|
2370
2361
|
}
|
|
2371
2362
|
}
|
|
2372
2363
|
catch (msgError) {
|
|
@@ -2376,8 +2367,8 @@ class AIPromptRunner {
|
|
|
2376
2367
|
category: 'PromptRunUpdate',
|
|
2377
2368
|
metadata: {
|
|
2378
2369
|
promptRunId: promptRun.ID,
|
|
2379
|
-
updateError: errorMsg
|
|
2380
|
-
}
|
|
2370
|
+
updateError: errorMsg,
|
|
2371
|
+
},
|
|
2381
2372
|
});
|
|
2382
2373
|
}
|
|
2383
2374
|
}
|
|
@@ -2385,8 +2376,8 @@ class AIPromptRunner {
|
|
|
2385
2376
|
this.logError(error, {
|
|
2386
2377
|
category: 'PromptRunUpdate',
|
|
2387
2378
|
metadata: {
|
|
2388
|
-
promptRunId: promptRun.ID
|
|
2389
|
-
}
|
|
2379
|
+
promptRunId: promptRun.ID,
|
|
2380
|
+
},
|
|
2390
2381
|
});
|
|
2391
2382
|
}
|
|
2392
2383
|
}
|
|
@@ -2396,7 +2387,7 @@ class AIPromptRunner {
|
|
|
2396
2387
|
maxAttempts: prompt.FailoverMaxAttempts || 3,
|
|
2397
2388
|
delaySeconds: prompt.FailoverDelaySeconds || 1,
|
|
2398
2389
|
modelStrategy: prompt.FailoverModelStrategy || 'PreferSameModel',
|
|
2399
|
-
errorScope: prompt.FailoverErrorScope || 'All'
|
|
2390
|
+
errorScope: prompt.FailoverErrorScope || 'All',
|
|
2400
2391
|
};
|
|
2401
2392
|
}
|
|
2402
2393
|
shouldAttemptFailover(error, config, attemptNumber) {
|
|
@@ -2413,8 +2404,7 @@ class AIPromptRunner {
|
|
|
2413
2404
|
case 'RateLimitOnly':
|
|
2414
2405
|
return errorAnalysis.errorType === 'RateLimit';
|
|
2415
2406
|
case 'ServiceErrorOnly':
|
|
2416
|
-
return errorAnalysis.errorType === 'ServiceUnavailable' ||
|
|
2417
|
-
errorAnalysis.errorType === 'InternalServerError';
|
|
2407
|
+
return errorAnalysis.errorType === 'ServiceUnavailable' || errorAnalysis.errorType === 'InternalServerError';
|
|
2418
2408
|
case 'All':
|
|
2419
2409
|
default:
|
|
2420
2410
|
return true;
|
|
@@ -2427,22 +2417,21 @@ class AIPromptRunner {
|
|
|
2427
2417
|
return totalDelay * 1000;
|
|
2428
2418
|
}
|
|
2429
2419
|
selectFailoverCandidates(currentModel, currentVendorId, strategy, modelStrategy, allCandidates, attemptHistory) {
|
|
2430
|
-
const failedPairs = new Set(attemptHistory.map(a => `${a.modelId}:${a.vendorId || 'default'}`));
|
|
2431
|
-
const availableCandidates = allCandidates.filter(c => {
|
|
2420
|
+
const failedPairs = new Set(attemptHistory.map((a) => `${a.modelId}:${a.vendorId || 'default'}`));
|
|
2421
|
+
const availableCandidates = allCandidates.filter((c) => {
|
|
2432
2422
|
const key = `${c.model.ID}:${c.vendorId || 'default'}`;
|
|
2433
2423
|
return !failedPairs.has(key);
|
|
2434
2424
|
});
|
|
2435
|
-
const hasContextLengthError = attemptHistory.some(a => a.errorType === 'ContextLengthExceeded' ||
|
|
2436
|
-
ai_1.ErrorAnalyzer.analyzeError(a.error).errorType === 'ContextLengthExceeded');
|
|
2425
|
+
const hasContextLengthError = attemptHistory.some((a) => a.errorType === 'ContextLengthExceeded' || ai_1.ErrorAnalyzer.analyzeError(a.error).errorType === 'ContextLengthExceeded');
|
|
2437
2426
|
let candidates;
|
|
2438
2427
|
switch (strategy) {
|
|
2439
2428
|
case 'SameModelDifferentVendor':
|
|
2440
|
-
candidates = availableCandidates.filter(c => c.model.ID === currentModel.ID && c.vendorId !== currentVendorId);
|
|
2429
|
+
candidates = availableCandidates.filter((c) => c.model.ID === currentModel.ID && c.vendorId !== currentVendorId);
|
|
2441
2430
|
break;
|
|
2442
2431
|
case 'NextBestModel':
|
|
2443
2432
|
candidates = availableCandidates;
|
|
2444
2433
|
if (modelStrategy === 'RequireSameModel') {
|
|
2445
|
-
candidates = candidates.filter(c => c.model.ID === currentModel.ID);
|
|
2434
|
+
candidates = candidates.filter((c) => c.model.ID === currentModel.ID);
|
|
2446
2435
|
}
|
|
2447
2436
|
else if (modelStrategy === 'PreferSameModel') {
|
|
2448
2437
|
candidates.sort((a, b) => {
|
|
@@ -2466,23 +2455,23 @@ class AIPromptRunner {
|
|
|
2466
2455
|
candidates = [];
|
|
2467
2456
|
}
|
|
2468
2457
|
if (hasContextLengthError) {
|
|
2469
|
-
const currentMaxTokens = currentModel.ModelVendors?.length > 0 ?
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
const candidateMaxTokens = c.model.ModelVendors?.length > 0 ?
|
|
2473
|
-
Math.max(...c.model.ModelVendors.map(mv => mv.MaxInputTokens || 0)) : 0;
|
|
2458
|
+
const currentMaxTokens = currentModel.ModelVendors?.length > 0 ? Math.max(...currentModel.ModelVendors.map((mv) => mv.MaxInputTokens || 0)) : 0;
|
|
2459
|
+
candidates = candidates.filter((c) => {
|
|
2460
|
+
const candidateMaxTokens = c.model.ModelVendors?.length > 0 ? Math.max(...c.model.ModelVendors.map((mv) => mv.MaxInputTokens || 0)) : 0;
|
|
2474
2461
|
return candidateMaxTokens > currentMaxTokens;
|
|
2475
2462
|
});
|
|
2476
2463
|
if (candidates.length === 0) {
|
|
2477
|
-
(0,
|
|
2464
|
+
(0, global_1.LogStatusEx)({
|
|
2478
2465
|
message: `❌ Context length exceeded and no models with larger context windows available. Current model: ${currentModel.Name} (${currentMaxTokens} max tokens). This is a fatal error.`,
|
|
2479
2466
|
category: 'AI',
|
|
2480
|
-
additionalArgs: [
|
|
2467
|
+
additionalArgs: [
|
|
2468
|
+
{
|
|
2481
2469
|
currentModel: currentModel.Name,
|
|
2482
2470
|
currentMaxTokens,
|
|
2483
|
-
availableModels: allCandidates.map(c => c.model.Name).join(', '),
|
|
2484
|
-
reason: 'No models with larger context windows available for failover'
|
|
2485
|
-
}
|
|
2471
|
+
availableModels: allCandidates.map((c) => c.model.Name).join(', '),
|
|
2472
|
+
reason: 'No models with larger context windows available for failover',
|
|
2473
|
+
},
|
|
2474
|
+
],
|
|
2486
2475
|
});
|
|
2487
2476
|
return [];
|
|
2488
2477
|
}
|
|
@@ -2490,25 +2479,26 @@ class AIPromptRunner {
|
|
|
2490
2479
|
if (a.priority !== b.priority) {
|
|
2491
2480
|
return b.priority - a.priority;
|
|
2492
2481
|
}
|
|
2493
|
-
const aMaxTokens = a.model.ModelVendors?.length > 0 ?
|
|
2494
|
-
|
|
2495
|
-
const bMaxTokens = b.model.ModelVendors?.length > 0 ?
|
|
2496
|
-
Math.max(...b.model.ModelVendors.map((mv) => mv.MaxInputTokens || 0)) : 0;
|
|
2482
|
+
const aMaxTokens = a.model.ModelVendors?.length > 0 ? Math.max(...a.model.ModelVendors.map((mv) => mv.MaxInputTokens || 0)) : 0;
|
|
2483
|
+
const bMaxTokens = b.model.ModelVendors?.length > 0 ? Math.max(...b.model.ModelVendors.map((mv) => mv.MaxInputTokens || 0)) : 0;
|
|
2497
2484
|
return bMaxTokens - aMaxTokens;
|
|
2498
2485
|
});
|
|
2499
2486
|
const bestCandidate = candidates[0];
|
|
2500
|
-
const bestCandidateMaxTokens = bestCandidate.model.ModelVendors?.length > 0
|
|
2501
|
-
Math.max(...bestCandidate.model.ModelVendors.map((mv) => mv.MaxInputTokens || 0))
|
|
2502
|
-
|
|
2487
|
+
const bestCandidateMaxTokens = bestCandidate.model.ModelVendors?.length > 0
|
|
2488
|
+
? Math.max(...bestCandidate.model.ModelVendors.map((mv) => mv.MaxInputTokens || 0))
|
|
2489
|
+
: 0;
|
|
2490
|
+
(0, global_1.LogStatusEx)({
|
|
2503
2491
|
message: `🔄 Context-aware failover: Selected model ${bestCandidate.model.Name} with ${bestCandidateMaxTokens} max input tokens (vs ${currentMaxTokens} for failed model)`,
|
|
2504
2492
|
category: 'AI',
|
|
2505
|
-
additionalArgs: [
|
|
2493
|
+
additionalArgs: [
|
|
2494
|
+
{
|
|
2506
2495
|
currentModel: currentModel.Name,
|
|
2507
2496
|
currentMaxTokens,
|
|
2508
2497
|
selectedModel: bestCandidate.model.Name,
|
|
2509
2498
|
selectedMaxTokens: bestCandidateMaxTokens,
|
|
2510
|
-
candidateCount: candidates.length
|
|
2511
|
-
}
|
|
2499
|
+
candidateCount: candidates.length,
|
|
2500
|
+
},
|
|
2501
|
+
],
|
|
2512
2502
|
});
|
|
2513
2503
|
}
|
|
2514
2504
|
else {
|
|
@@ -2526,22 +2516,22 @@ class AIPromptRunner {
|
|
|
2526
2516
|
errorType: attempt.errorType,
|
|
2527
2517
|
duration: attempt.duration,
|
|
2528
2518
|
willRetry,
|
|
2529
|
-
error: attempt.error.message
|
|
2519
|
+
error: attempt.error.message,
|
|
2530
2520
|
};
|
|
2531
2521
|
if (willRetry) {
|
|
2532
|
-
(0,
|
|
2522
|
+
(0, global_1.LogStatusEx)({
|
|
2533
2523
|
message: `⚡ ${message}`,
|
|
2534
2524
|
category: 'AI',
|
|
2535
|
-
additionalArgs: [metadata]
|
|
2525
|
+
additionalArgs: [metadata],
|
|
2536
2526
|
});
|
|
2537
2527
|
}
|
|
2538
2528
|
else {
|
|
2539
|
-
(0,
|
|
2529
|
+
(0, global_1.LogErrorEx)({
|
|
2540
2530
|
message: message,
|
|
2541
2531
|
error: attempt.error,
|
|
2542
2532
|
category: 'AI',
|
|
2543
2533
|
severity: 'error',
|
|
2544
|
-
metadata: metadata
|
|
2534
|
+
metadata: metadata,
|
|
2545
2535
|
});
|
|
2546
2536
|
}
|
|
2547
2537
|
}
|