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