@memberjunction/ai-prompts 5.4.1 → 5.6.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.js +61 -61
- package/dist/AIPromptRunner.js.map +1 -1
- package/dist/ExecutionPlanner.d.ts.map +1 -1
- package/dist/ExecutionPlanner.js +15 -14
- package/dist/ExecutionPlanner.js.map +1 -1
- package/dist/ParallelExecutionCoordinator.js +2 -2
- package/dist/ParallelExecutionCoordinator.js.map +1 -1
- package/package.json +11 -11
package/dist/AIPromptRunner.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseLLM, ChatParams, ChatMessageRole, GetAIAPIKey, ErrorAnalyzer } from '@memberjunction/ai';
|
|
2
2
|
import { AIModelSelectionInfo } from '@memberjunction/ai-core-plus';
|
|
3
3
|
import { LogErrorEx, LogStatus, LogStatusEx, IsVerboseLoggingEnabled, Metadata } from '@memberjunction/core';
|
|
4
|
-
import { CleanJSON, MJGlobal, JSONValidator, ValidationResult, ValidationErrorInfo, ValidationErrorType } from '@memberjunction/global';
|
|
4
|
+
import { CleanJSON, MJGlobal, JSONValidator, ValidationResult, ValidationErrorInfo, ValidationErrorType, UUIDsEqual, NormalizeUUID } from '@memberjunction/global';
|
|
5
5
|
import { CredentialEngine } from '@memberjunction/credentials';
|
|
6
6
|
import { TemplateEngineServer } from '@memberjunction/templates';
|
|
7
7
|
import { ExecutionPlanner } from './ExecutionPlanner.js';
|
|
@@ -90,9 +90,9 @@ export class AIPromptRunner {
|
|
|
90
90
|
if (!inferenceProviderType) {
|
|
91
91
|
// Fallback to checking if it's not a model developer (should rarely happen)
|
|
92
92
|
const modelDeveloperType = AIEngine.Instance.VendorTypeDefinitions.find(vt => vt.Name === 'Model Developer');
|
|
93
|
-
return modelVendor.TypeID
|
|
93
|
+
return !UUIDsEqual(modelVendor.TypeID, modelDeveloperType?.ID);
|
|
94
94
|
}
|
|
95
|
-
return modelVendor.TypeID
|
|
95
|
+
return UUIDsEqual(modelVendor.TypeID, inferenceProviderType.ID);
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
98
|
* Resolves credentials for AI model execution using a hierarchical resolution system.
|
|
@@ -125,7 +125,7 @@ export class AIPromptRunner {
|
|
|
125
125
|
await CredentialEngine.Instance.Config(false, params.contextUser);
|
|
126
126
|
// Priority 2: PromptModel bindings (most specific) - with failover
|
|
127
127
|
if (promptId && modelId) {
|
|
128
|
-
const promptModel = AIEngine.Instance.PromptModels.find(pm => pm.PromptID
|
|
128
|
+
const promptModel = AIEngine.Instance.PromptModels.find(pm => UUIDsEqual(pm.PromptID, promptId) && UUIDsEqual(pm.ModelID, modelId));
|
|
129
129
|
if (promptModel) {
|
|
130
130
|
const bindings = AIEngine.Instance.GetCredentialBindingsForTarget('PromptModel', promptModel.ID);
|
|
131
131
|
const result = await this.tryCredentialBindingsWithFailover(bindings, 'AICredentialBinding(PromptModel)', params, verbose);
|
|
@@ -135,7 +135,7 @@ export class AIPromptRunner {
|
|
|
135
135
|
}
|
|
136
136
|
// Priority 3: ModelVendor bindings - with failover
|
|
137
137
|
if (modelId && vendorId) {
|
|
138
|
-
const modelVendor = AIEngine.Instance.ModelVendors.find(mv => mv.ModelID
|
|
138
|
+
const modelVendor = AIEngine.Instance.ModelVendors.find(mv => UUIDsEqual(mv.ModelID, modelId) && UUIDsEqual(mv.VendorID, vendorId) && mv.Status === 'Active');
|
|
139
139
|
if (modelVendor) {
|
|
140
140
|
const bindings = AIEngine.Instance.GetCredentialBindingsForTarget('ModelVendor', modelVendor.ID);
|
|
141
141
|
const result = await this.tryCredentialBindingsWithFailover(bindings, 'AICredentialBinding(ModelVendor)', params, verbose);
|
|
@@ -153,7 +153,7 @@ export class AIPromptRunner {
|
|
|
153
153
|
// Priority 5: Type-based default credential
|
|
154
154
|
// If the vendor declares a CredentialTypeID, try to find a default credential of that type
|
|
155
155
|
if (vendorId) {
|
|
156
|
-
const vendor = AIEngine.Instance.Vendors.find(v => v.ID
|
|
156
|
+
const vendor = AIEngine.Instance.Vendors.find(v => UUIDsEqual(v.ID, vendorId));
|
|
157
157
|
if (vendor?.CredentialTypeID) {
|
|
158
158
|
const defaultCredential = this.findDefaultCredentialByType(vendor.CredentialTypeID);
|
|
159
159
|
if (defaultCredential) {
|
|
@@ -271,7 +271,7 @@ export class AIPromptRunner {
|
|
|
271
271
|
*/
|
|
272
272
|
findDefaultCredentialByType(credentialTypeId) {
|
|
273
273
|
const credentials = CredentialEngine.Instance.Credentials;
|
|
274
|
-
return credentials.find(c => c.CredentialTypeID
|
|
274
|
+
return credentials.find(c => UUIDsEqual(c.CredentialTypeID, credentialTypeId) &&
|
|
275
275
|
c.IsDefault === true &&
|
|
276
276
|
c.IsActive === true &&
|
|
277
277
|
(!c.ExpiresAt || new Date(c.ExpiresAt) > new Date())) || null;
|
|
@@ -305,14 +305,14 @@ export class AIPromptRunner {
|
|
|
305
305
|
}
|
|
306
306
|
// Priority 2: PromptModel bindings
|
|
307
307
|
if (promptId && modelId) {
|
|
308
|
-
const promptModel = AIEngine.Instance.PromptModels.find(pm => pm.PromptID
|
|
308
|
+
const promptModel = AIEngine.Instance.PromptModels.find(pm => UUIDsEqual(pm.PromptID, promptId) && UUIDsEqual(pm.ModelID, modelId));
|
|
309
309
|
if (promptModel && AIEngine.Instance.HasCredentialBindings('PromptModel', promptModel.ID)) {
|
|
310
310
|
return true;
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
// Priority 3: ModelVendor bindings
|
|
314
314
|
if (modelId && vendorId) {
|
|
315
|
-
const modelVendor = AIEngine.Instance.ModelVendors.find(mv => mv.ModelID
|
|
315
|
+
const modelVendor = AIEngine.Instance.ModelVendors.find(mv => UUIDsEqual(mv.ModelID, modelId) && UUIDsEqual(mv.VendorID, vendorId) && mv.Status === 'Active');
|
|
316
316
|
if (modelVendor && AIEngine.Instance.HasCredentialBindings('ModelVendor', modelVendor.ID)) {
|
|
317
317
|
return true;
|
|
318
318
|
}
|
|
@@ -325,7 +325,7 @@ export class AIPromptRunner {
|
|
|
325
325
|
}
|
|
326
326
|
// Priority 5: Type-based default credential
|
|
327
327
|
if (vendorId) {
|
|
328
|
-
const vendor = AIEngine.Instance.Vendors.find(v => v.ID
|
|
328
|
+
const vendor = AIEngine.Instance.Vendors.find(v => UUIDsEqual(v.ID, vendorId));
|
|
329
329
|
if (vendor?.CredentialTypeID) {
|
|
330
330
|
const defaultCredential = this.findDefaultCredentialByType(vendor.CredentialTypeID);
|
|
331
331
|
if (defaultCredential) {
|
|
@@ -562,8 +562,8 @@ export class AIPromptRunner {
|
|
|
562
562
|
// we received model selection info, need to lookup vendor driver class and api name from there
|
|
563
563
|
const vendorID = modelSelectionInfo.vendorSelected?.ID;
|
|
564
564
|
const modelID = modelSelectionInfo.modelSelected.ID;
|
|
565
|
-
const modelVendor = AIEngine.Instance.ModelVendors.find(mv => mv.VendorID
|
|
566
|
-
mv.ModelID
|
|
565
|
+
const modelVendor = AIEngine.Instance.ModelVendors.find(mv => UUIDsEqual(mv.VendorID, vendorID) &&
|
|
566
|
+
UUIDsEqual(mv.ModelID, modelID));
|
|
567
567
|
if (modelVendor) {
|
|
568
568
|
vendorDriverClass = modelVendor.DriverClass;
|
|
569
569
|
vendorApiName = modelVendor.APIName;
|
|
@@ -684,9 +684,9 @@ export class AIPromptRunner {
|
|
|
684
684
|
this.logStatus(` Using prompt "${modelSelectionPrompt.Name}" for model selection in parallel execution`, true, params);
|
|
685
685
|
}
|
|
686
686
|
// Get prompt-specific model associations using the model selection prompt
|
|
687
|
-
const promptModels = AIEngine.Instance.PromptModels.filter((pm) => pm.PromptID
|
|
687
|
+
const promptModels = AIEngine.Instance.PromptModels.filter((pm) => UUIDsEqual(pm.PromptID, modelSelectionPrompt.ID) &&
|
|
688
688
|
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
689
|
-
(!params.configurationId || !pm.ConfigurationID || pm.ConfigurationID
|
|
689
|
+
(!params.configurationId || !pm.ConfigurationID || UUIDsEqual(pm.ConfigurationID, params.configurationId)));
|
|
690
690
|
// Create execution plan using the modelSelectionPrompt for model configurations
|
|
691
691
|
executionTasks = this._executionPlanner.createExecutionPlan(modelSelectionPrompt, promptModels, AIEngine.Instance.Models, renderedPromptText, params.contextUser, params.configurationId, params.conversationMessages, params.templateMessageRole || 'system');
|
|
692
692
|
}
|
|
@@ -875,7 +875,7 @@ export class AIPromptRunner {
|
|
|
875
875
|
async loadTemplate(templateId, _contextUser) {
|
|
876
876
|
try {
|
|
877
877
|
// Use the template engine to find the template
|
|
878
|
-
const template = this._templateEngine.Templates.find((t) => t.ID
|
|
878
|
+
const template = this._templateEngine.Templates.find((t) => UUIDsEqual(t.ID, templateId));
|
|
879
879
|
return template || null;
|
|
880
880
|
}
|
|
881
881
|
catch (error) {
|
|
@@ -1089,7 +1089,7 @@ export class AIPromptRunner {
|
|
|
1089
1089
|
}
|
|
1090
1090
|
// Get configuration info if provided
|
|
1091
1091
|
if (configurationId) {
|
|
1092
|
-
configuration = AIEngine.Instance.Configurations.find(c => c.ID
|
|
1092
|
+
configuration = AIEngine.Instance.Configurations.find(c => UUIDsEqual(c.ID, configurationId));
|
|
1093
1093
|
configurationName = configuration?.Name;
|
|
1094
1094
|
}
|
|
1095
1095
|
// Build unified list of model-vendor candidates
|
|
@@ -1170,7 +1170,7 @@ export class AIPromptRunner {
|
|
|
1170
1170
|
// Get selected vendor entity
|
|
1171
1171
|
let selectedVendor;
|
|
1172
1172
|
if (selected.vendorId) {
|
|
1173
|
-
selectedVendor = AIEngine.Instance.Vendors.find(v => v.ID
|
|
1173
|
+
selectedVendor = AIEngine.Instance.Vendors.find(v => UUIDsEqual(v.ID, selected.vendorId));
|
|
1174
1174
|
}
|
|
1175
1175
|
return {
|
|
1176
1176
|
model: selected.model,
|
|
@@ -1246,12 +1246,12 @@ export class AIPromptRunner {
|
|
|
1246
1246
|
* Returns candidates for the single model if it's active and compatible.
|
|
1247
1247
|
*/
|
|
1248
1248
|
buildCandidatesForExplicitModel(explicitModelId, prompt, preferredVendorId) {
|
|
1249
|
-
const model = AIEngine.Instance.Models.find(m => m.ID
|
|
1249
|
+
const model = AIEngine.Instance.Models.find(m => UUIDsEqual(m.ID, explicitModelId));
|
|
1250
1250
|
if (!model || !model.IsActive) {
|
|
1251
1251
|
return [];
|
|
1252
1252
|
}
|
|
1253
1253
|
// Check model type compatibility
|
|
1254
|
-
if (prompt.AIModelTypeID && model.AIModelTypeID
|
|
1254
|
+
if (prompt.AIModelTypeID && !UUIDsEqual(model.AIModelTypeID, prompt.AIModelTypeID)) {
|
|
1255
1255
|
return [];
|
|
1256
1256
|
}
|
|
1257
1257
|
const candidates = this.createCandidatesForModel(model, 20000, 'explicit', preferredVendorId);
|
|
@@ -1266,7 +1266,7 @@ export class AIPromptRunner {
|
|
|
1266
1266
|
*/
|
|
1267
1267
|
buildCandidatesForSpecificStrategy(prompt, configurationId, verbose) {
|
|
1268
1268
|
// Get all active AIPromptModel records for this prompt
|
|
1269
|
-
const allPromptModels = AIEngine.Instance.PromptModels.filter(pm => pm.PromptID
|
|
1269
|
+
const allPromptModels = AIEngine.Instance.PromptModels.filter(pm => UUIDsEqual(pm.PromptID, prompt.ID) && (pm.Status === 'Active' || pm.Status === 'Preview'));
|
|
1270
1270
|
// Filter by configuration matching rules
|
|
1271
1271
|
const promptModels = this.filterPromptModelsByConfiguration(allPromptModels, configurationId);
|
|
1272
1272
|
// Sort: config-specific before universal, then by priority DESC within each group
|
|
@@ -1290,7 +1290,7 @@ export class AIPromptRunner {
|
|
|
1290
1290
|
*/
|
|
1291
1291
|
buildCandidatesForGeneralSelection(prompt, configurationId, preferredVendorId, verbose) {
|
|
1292
1292
|
const preferredVendorName = preferredVendorId ?
|
|
1293
|
-
AIEngine.Instance.Vendors.find(v => v.ID
|
|
1293
|
+
AIEngine.Instance.Vendors.find(v => UUIDsEqual(v.ID, preferredVendorId))?.Name : undefined;
|
|
1294
1294
|
// Get prompt models for configuration
|
|
1295
1295
|
const promptModels = this.getPromptModelsForConfiguration(prompt, configurationId);
|
|
1296
1296
|
const candidates = [];
|
|
@@ -1318,9 +1318,9 @@ export class AIPromptRunner {
|
|
|
1318
1318
|
if (configurationId) {
|
|
1319
1319
|
// Get the configuration inheritance chain
|
|
1320
1320
|
const chain = AIEngine.Instance.GetConfigurationChain(configurationId);
|
|
1321
|
-
const chainIds = new Set(chain.map(c => c.ID));
|
|
1321
|
+
const chainIds = new Set(chain.map(c => NormalizeUUID(c.ID)));
|
|
1322
1322
|
// Include models matching any config in the chain, plus null-config (universal fallback)
|
|
1323
|
-
return allPromptModels.filter(pm => (pm.ConfigurationID && chainIds.has(pm.ConfigurationID)) ||
|
|
1323
|
+
return allPromptModels.filter(pm => (pm.ConfigurationID && chainIds.has(NormalizeUUID(pm.ConfigurationID))) ||
|
|
1324
1324
|
pm.ConfigurationID === null);
|
|
1325
1325
|
}
|
|
1326
1326
|
else {
|
|
@@ -1359,7 +1359,7 @@ export class AIPromptRunner {
|
|
|
1359
1359
|
buildCandidatesFromPromptModels(promptModels) {
|
|
1360
1360
|
const candidates = [];
|
|
1361
1361
|
for (const pm of promptModels) {
|
|
1362
|
-
const model = AIEngine.Instance.Models.find(m => m.ID
|
|
1362
|
+
const model = AIEngine.Instance.Models.find(m => UUIDsEqual(m.ID, pm.ModelID));
|
|
1363
1363
|
if (!model || !model.IsActive)
|
|
1364
1364
|
continue;
|
|
1365
1365
|
if (pm.VendorID) {
|
|
@@ -1381,8 +1381,8 @@ export class AIPromptRunner {
|
|
|
1381
1381
|
* Helper: Create candidate for specific vendor from AIPromptModel.
|
|
1382
1382
|
*/
|
|
1383
1383
|
createCandidateForSpecificVendor(model, promptModel) {
|
|
1384
|
-
const modelVendor = AIEngine.Instance.ModelVendors.find(mv => mv.ModelID
|
|
1385
|
-
mv.VendorID
|
|
1384
|
+
const modelVendor = AIEngine.Instance.ModelVendors.find(mv => UUIDsEqual(mv.ModelID, promptModel.ModelID) &&
|
|
1385
|
+
UUIDsEqual(mv.VendorID, promptModel.VendorID) &&
|
|
1386
1386
|
mv.Status === 'Active' &&
|
|
1387
1387
|
this.isInferenceProvider(mv));
|
|
1388
1388
|
if (!modelVendor)
|
|
@@ -1405,7 +1405,7 @@ export class AIPromptRunner {
|
|
|
1405
1405
|
*/
|
|
1406
1406
|
createCandidatesForAllVendors(model) {
|
|
1407
1407
|
const vendors = AIEngine.Instance.ModelVendors
|
|
1408
|
-
.filter(mv => mv.ModelID
|
|
1408
|
+
.filter(mv => UUIDsEqual(mv.ModelID, model.ID) &&
|
|
1409
1409
|
mv.Status === 'Active' &&
|
|
1410
1410
|
this.isInferenceProvider(mv))
|
|
1411
1411
|
.sort((a, b) => (b.Priority || 0) - (a.Priority || 0));
|
|
@@ -1448,9 +1448,9 @@ export class AIPromptRunner {
|
|
|
1448
1448
|
const chain = AIEngine.Instance.GetConfigurationChain(configurationId);
|
|
1449
1449
|
// Walk the chain looking for prompt models
|
|
1450
1450
|
for (const config of chain) {
|
|
1451
|
-
const promptModels = AIEngine.Instance.PromptModels.filter(pm => pm.PromptID
|
|
1451
|
+
const promptModels = AIEngine.Instance.PromptModels.filter(pm => UUIDsEqual(pm.PromptID, prompt.ID) &&
|
|
1452
1452
|
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
1453
|
-
pm.ConfigurationID
|
|
1453
|
+
UUIDsEqual(pm.ConfigurationID, config.ID));
|
|
1454
1454
|
if (promptModels.length > 0) {
|
|
1455
1455
|
return promptModels;
|
|
1456
1456
|
}
|
|
@@ -1459,7 +1459,7 @@ export class AIPromptRunner {
|
|
|
1459
1459
|
LogStatus(`No models found in configuration chain for "${configurationId}", falling back to default models`);
|
|
1460
1460
|
}
|
|
1461
1461
|
// Return null-config (universal) models
|
|
1462
|
-
return AIEngine.Instance.PromptModels.filter(pm => pm.PromptID
|
|
1462
|
+
return AIEngine.Instance.PromptModels.filter(pm => UUIDsEqual(pm.PromptID, prompt.ID) &&
|
|
1463
1463
|
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
1464
1464
|
!pm.ConfigurationID);
|
|
1465
1465
|
}
|
|
@@ -1468,7 +1468,7 @@ export class AIPromptRunner {
|
|
|
1468
1468
|
*/
|
|
1469
1469
|
addPromptSpecificCandidates(candidates, promptModels, preferredVendorId) {
|
|
1470
1470
|
for (const pm of promptModels) {
|
|
1471
|
-
const model = AIEngine.Instance.Models.find(m => m.ID
|
|
1471
|
+
const model = AIEngine.Instance.Models.find(m => UUIDsEqual(m.ID, pm.ModelID));
|
|
1472
1472
|
if (model && model.IsActive) {
|
|
1473
1473
|
const modelCandidates = this.createCandidatesForModel(model, 5000, 'prompt-model', preferredVendorId, pm.Priority);
|
|
1474
1474
|
candidates.push(...modelCandidates);
|
|
@@ -1484,14 +1484,14 @@ export class AIPromptRunner {
|
|
|
1484
1484
|
// Add models from parent configs (skip index 0 which is the direct config, already handled)
|
|
1485
1485
|
for (let i = 1; i < chain.length; i++) {
|
|
1486
1486
|
const parentConfig = chain[i];
|
|
1487
|
-
const parentModels = AIEngine.Instance.PromptModels.filter(pm => pm.PromptID
|
|
1487
|
+
const parentModels = AIEngine.Instance.PromptModels.filter(pm => UUIDsEqual(pm.PromptID, prompt.ID) &&
|
|
1488
1488
|
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
1489
|
-
pm.ConfigurationID
|
|
1489
|
+
UUIDsEqual(pm.ConfigurationID, parentConfig.ID));
|
|
1490
1490
|
if (parentModels.length > 0 && verbose) {
|
|
1491
1491
|
LogStatus(`Adding ${parentModels.length} models from parent config "${parentConfig.Name}" as fallback`);
|
|
1492
1492
|
}
|
|
1493
1493
|
for (const pm of parentModels) {
|
|
1494
|
-
const model = AIEngine.Instance.Models.find(m => m.ID
|
|
1494
|
+
const model = AIEngine.Instance.Models.find(m => UUIDsEqual(m.ID, pm.ModelID));
|
|
1495
1495
|
if (model && model.IsActive) {
|
|
1496
1496
|
// Decrease base priority for each level up the chain (3000, 2500, 2000, etc.)
|
|
1497
1497
|
const basePriority = 3000 - (i * 500);
|
|
@@ -1501,14 +1501,14 @@ export class AIPromptRunner {
|
|
|
1501
1501
|
}
|
|
1502
1502
|
}
|
|
1503
1503
|
// Finally add NULL config models (universal fallback) with lowest priority
|
|
1504
|
-
const nullConfigModels = AIEngine.Instance.PromptModels.filter(pm => pm.PromptID
|
|
1504
|
+
const nullConfigModels = AIEngine.Instance.PromptModels.filter(pm => UUIDsEqual(pm.PromptID, prompt.ID) &&
|
|
1505
1505
|
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
1506
1506
|
!pm.ConfigurationID);
|
|
1507
1507
|
if (nullConfigModels.length > 0 && verbose) {
|
|
1508
1508
|
LogStatus(`Adding ${nullConfigModels.length} NULL configuration models as universal fallback`);
|
|
1509
1509
|
}
|
|
1510
1510
|
for (const pm of nullConfigModels) {
|
|
1511
|
-
const model = AIEngine.Instance.Models.find(m => m.ID
|
|
1511
|
+
const model = AIEngine.Instance.Models.find(m => UUIDsEqual(m.ID, pm.ModelID));
|
|
1512
1512
|
if (model && model.IsActive) {
|
|
1513
1513
|
const modelCandidates = this.createCandidatesForModel(model, 1000, // Lowest priority tier
|
|
1514
1514
|
'prompt-model', preferredVendorId, pm.Priority);
|
|
@@ -1534,9 +1534,9 @@ export class AIPromptRunner {
|
|
|
1534
1534
|
*/
|
|
1535
1535
|
getModelPoolForStrategy(prompt, preferredVendorName) {
|
|
1536
1536
|
return AIEngine.Instance.Models.filter(m => m.IsActive &&
|
|
1537
|
-
(!prompt.AIModelTypeID || m.AIModelTypeID
|
|
1537
|
+
(!prompt.AIModelTypeID || UUIDsEqual(m.AIModelTypeID, prompt.AIModelTypeID)) &&
|
|
1538
1538
|
(!preferredVendorName ||
|
|
1539
|
-
AIEngine.Instance.ModelVendors.some(mv => mv.ModelID
|
|
1539
|
+
AIEngine.Instance.ModelVendors.some(mv => UUIDsEqual(mv.ModelID, m.ID) &&
|
|
1540
1540
|
mv.Status === 'Active' &&
|
|
1541
1541
|
mv.Vendor === preferredVendorName &&
|
|
1542
1542
|
this.isInferenceProvider(mv))));
|
|
@@ -1580,11 +1580,11 @@ export class AIPromptRunner {
|
|
|
1580
1580
|
const modelCandidates = [];
|
|
1581
1581
|
// Get all vendors for this model - filter for inference providers only
|
|
1582
1582
|
const modelVendors = AIEngine.Instance.ModelVendors
|
|
1583
|
-
.filter(mv => mv.ModelID
|
|
1583
|
+
.filter(mv => UUIDsEqual(mv.ModelID, model.ID) && mv.Status === 'Active' && this.isInferenceProvider(mv))
|
|
1584
1584
|
.sort((a, b) => b.Priority - a.Priority);
|
|
1585
1585
|
// First, add preferred vendor if it exists
|
|
1586
1586
|
if (preferredVendorId) {
|
|
1587
|
-
const preferredVendor = modelVendors.find(mv => mv.VendorID
|
|
1587
|
+
const preferredVendor = modelVendors.find(mv => UUIDsEqual(mv.VendorID, preferredVendorId));
|
|
1588
1588
|
if (preferredVendor) {
|
|
1589
1589
|
modelCandidates.push({
|
|
1590
1590
|
model,
|
|
@@ -1601,7 +1601,7 @@ export class AIPromptRunner {
|
|
|
1601
1601
|
}
|
|
1602
1602
|
// Then add other vendors in priority order
|
|
1603
1603
|
for (const vendor of modelVendors) {
|
|
1604
|
-
if (vendor.VendorID
|
|
1604
|
+
if (!UUIDsEqual(vendor.VendorID, preferredVendorId)) {
|
|
1605
1605
|
modelCandidates.push({
|
|
1606
1606
|
model,
|
|
1607
1607
|
vendorId: vendor.VendorID,
|
|
@@ -1654,8 +1654,8 @@ export class AIPromptRunner {
|
|
|
1654
1654
|
return validModels.map(considered => {
|
|
1655
1655
|
// Find matching model vendor for driver and API info
|
|
1656
1656
|
const modelVendor = considered.vendor
|
|
1657
|
-
? AIEngine.Instance.ModelVendors.find(mv => mv.ModelID
|
|
1658
|
-
mv.VendorID
|
|
1657
|
+
? AIEngine.Instance.ModelVendors.find(mv => UUIDsEqual(mv.ModelID, considered.model.ID) &&
|
|
1658
|
+
UUIDsEqual(mv.VendorID, considered.vendor.ID))
|
|
1659
1659
|
: undefined;
|
|
1660
1660
|
return {
|
|
1661
1661
|
model: considered.model,
|
|
@@ -1702,7 +1702,7 @@ export class AIPromptRunner {
|
|
|
1702
1702
|
// Get vendor entity from AIEngine cache if vendorId is available
|
|
1703
1703
|
let vendorEntity;
|
|
1704
1704
|
if (candidate.vendorId) {
|
|
1705
|
-
vendorEntity = AIEngine.Instance.Vendors.find(v => v.ID
|
|
1705
|
+
vendorEntity = AIEngine.Instance.Vendors.find(v => UUIDsEqual(v.ID, candidate.vendorId));
|
|
1706
1706
|
}
|
|
1707
1707
|
// Track this model as considered with availability status
|
|
1708
1708
|
consideredModels.push({
|
|
@@ -1715,8 +1715,8 @@ export class AIPromptRunner {
|
|
|
1715
1715
|
}
|
|
1716
1716
|
// Select the first available candidate (highest priority with API key)
|
|
1717
1717
|
const selected = consideredModels.find(m => m.available);
|
|
1718
|
-
const selectedCandidate = selected ? candidates.find(c => c.model.ID
|
|
1719
|
-
c.vendorId
|
|
1718
|
+
const selectedCandidate = selected ? candidates.find(c => UUIDsEqual(c.model.ID, selected.model.ID) &&
|
|
1719
|
+
UUIDsEqual(c.vendorId, selected.vendor?.ID)) : null;
|
|
1720
1720
|
if (selectedCandidate) {
|
|
1721
1721
|
const validCount = consideredModels.filter(m => m.available).length;
|
|
1722
1722
|
this.logStatus(` Selected model ${selectedCandidate.model.Name} with ${selectedCandidate.vendorName || 'default'} vendor (driver: ${selectedCandidate.driverClass})`, true);
|
|
@@ -1807,7 +1807,7 @@ export class AIPromptRunner {
|
|
|
1807
1807
|
else {
|
|
1808
1808
|
// Fallback: grab the highest priority AI Model Vendor record for this model (inference providers only)
|
|
1809
1809
|
const modelVendors = AIEngine.Instance.ModelVendors
|
|
1810
|
-
.filter((mv) => mv.ModelID
|
|
1810
|
+
.filter((mv) => UUIDsEqual(mv.ModelID, model.ID) && mv.Status === 'Active' && this.isInferenceProvider(mv))
|
|
1811
1811
|
.sort((a, b) => b.Priority - a.Priority);
|
|
1812
1812
|
if (modelVendors.length > 0) {
|
|
1813
1813
|
promptRun.VendorID = modelVendors[0].VendorID;
|
|
@@ -2100,7 +2100,7 @@ export class AIPromptRunner {
|
|
|
2100
2100
|
let allModels;
|
|
2101
2101
|
if (prompt.AIModelTypeID) {
|
|
2102
2102
|
// Find the model type from the prompt
|
|
2103
|
-
const modelType = aiEngine.ModelTypes.find(mt => mt.ID
|
|
2103
|
+
const modelType = aiEngine.ModelTypes.find(mt => UUIDsEqual(mt.ID, prompt.AIModelTypeID));
|
|
2104
2104
|
if (!modelType) {
|
|
2105
2105
|
throw new Error(`Model type ${prompt.AIModelTypeID} not found`);
|
|
2106
2106
|
}
|
|
@@ -2172,10 +2172,10 @@ export class AIPromptRunner {
|
|
|
2172
2172
|
promptRun.FailoverDurations = JSON.stringify(failoverAttempts.map(a => a.duration));
|
|
2173
2173
|
promptRun.TotalFailoverDuration = failoverAttempts.reduce((sum, a) => sum + a.duration, 0);
|
|
2174
2174
|
// Update ModelID if we ended up using a different model
|
|
2175
|
-
if (currentModel.ID
|
|
2175
|
+
if (!UUIDsEqual(currentModel.ID, promptRun.OriginalModelID)) {
|
|
2176
2176
|
promptRun.ModelID = currentModel.ID;
|
|
2177
2177
|
}
|
|
2178
|
-
if (currentVendorId && currentVendorId
|
|
2178
|
+
if (currentVendorId && !UUIDsEqual(currentVendorId, promptRun.VendorID)) {
|
|
2179
2179
|
promptRun.VendorID = currentVendorId;
|
|
2180
2180
|
}
|
|
2181
2181
|
}
|
|
@@ -2254,7 +2254,7 @@ export class AIPromptRunner {
|
|
|
2254
2254
|
supportsEffortLevel = model.SupportsEffortLevel ?? false;
|
|
2255
2255
|
if (vendorId) {
|
|
2256
2256
|
// Find the AIModelVendor record for this specific vendor - must be an inference provider
|
|
2257
|
-
const modelVendor = AIEngine.Instance.ModelVendors.find((mv) => mv.ModelID
|
|
2257
|
+
const modelVendor = AIEngine.Instance.ModelVendors.find((mv) => UUIDsEqual(mv.ModelID, model.ID) && UUIDsEqual(mv.VendorID, vendorId) && mv.Status === 'Active' && this.isInferenceProvider(mv));
|
|
2258
2258
|
if (modelVendor) {
|
|
2259
2259
|
driverClass = modelVendor.DriverClass || driverClass;
|
|
2260
2260
|
apiName = modelVendor.APIName || apiName;
|
|
@@ -2635,7 +2635,7 @@ export class AIPromptRunner {
|
|
|
2635
2635
|
const filteredCandidates = allCandidates.filter(c => (c.vendorId || 'default') !== failedVendorId);
|
|
2636
2636
|
const removedCount = beforeCount - filteredCandidates.length;
|
|
2637
2637
|
if (removedCount > 0) {
|
|
2638
|
-
const vendorName = AIEngine.Instance.Vendors.find(v => v.ID
|
|
2638
|
+
const vendorName = AIEngine.Instance.Vendors.find(v => UUIDsEqual(v.ID, failedVendorId))?.Name || failedVendorId;
|
|
2639
2639
|
const remainingCount = filteredCandidates.length;
|
|
2640
2640
|
// Log appropriate message based on error type
|
|
2641
2641
|
let reason;
|
|
@@ -2666,8 +2666,8 @@ export class AIPromptRunner {
|
|
|
2666
2666
|
return false; // Not a rate limit error
|
|
2667
2667
|
}
|
|
2668
2668
|
// Count how many times we've retried this specific model/vendor for rate limits
|
|
2669
|
-
const rateLimitRetryCount = failoverAttempts.filter(a => a.modelId
|
|
2670
|
-
a.vendorId
|
|
2669
|
+
const rateLimitRetryCount = failoverAttempts.filter(a => UUIDsEqual(a.modelId, currentModel.ID) &&
|
|
2670
|
+
UUIDsEqual(a.vendorId, currentVendorId) &&
|
|
2671
2671
|
a.errorType === 'RateLimit').length;
|
|
2672
2672
|
// Use MaxRetries from prompt configuration, default to 3 if not set
|
|
2673
2673
|
const maxRetries = prompt.MaxRetries ?? 3;
|
|
@@ -2676,7 +2676,7 @@ export class AIPromptRunner {
|
|
|
2676
2676
|
if (shouldRetry) {
|
|
2677
2677
|
const modelName = currentModel.Name;
|
|
2678
2678
|
const vendorName = currentVendorId
|
|
2679
|
-
? AIEngine.Instance.Vendors.find(v => v.ID
|
|
2679
|
+
? AIEngine.Instance.Vendors.find(v => UUIDsEqual(v.ID, currentVendorId))?.Name || 'default'
|
|
2680
2680
|
: 'default';
|
|
2681
2681
|
this.logStatus(` ⏳ Rate limit hit - retrying ${modelName} (${vendorName}) with backoff (attempt ${rateLimitRetryCount}/${maxRetries})`, true);
|
|
2682
2682
|
this.logFailoverAttempt(prompt.ID, failoverAttempt, true);
|
|
@@ -3662,27 +3662,27 @@ export class AIPromptRunner {
|
|
|
3662
3662
|
switch (strategy) {
|
|
3663
3663
|
case 'SameModelDifferentVendor':
|
|
3664
3664
|
// Only consider same model with different vendors
|
|
3665
|
-
candidates = availableCandidates.filter(c => c.model.ID
|
|
3665
|
+
candidates = availableCandidates.filter(c => UUIDsEqual(c.model.ID, currentModel.ID) && !UUIDsEqual(c.vendorId, currentVendorId));
|
|
3666
3666
|
break;
|
|
3667
3667
|
case 'NextBestModel':
|
|
3668
3668
|
// Consider all models, apply model strategy preference
|
|
3669
3669
|
candidates = availableCandidates;
|
|
3670
3670
|
if (modelStrategy === 'RequireSameModel') {
|
|
3671
|
-
candidates = candidates.filter(c => c.model.ID
|
|
3671
|
+
candidates = candidates.filter(c => UUIDsEqual(c.model.ID, currentModel.ID));
|
|
3672
3672
|
}
|
|
3673
3673
|
else if (modelStrategy === 'PreferSameModel') {
|
|
3674
3674
|
// Sort to put same model first
|
|
3675
3675
|
candidates.sort((a, b) => {
|
|
3676
|
-
const aSameModel = a.model.ID
|
|
3677
|
-
const bSameModel = b.model.ID
|
|
3676
|
+
const aSameModel = UUIDsEqual(a.model.ID, currentModel.ID) ? 1 : 0;
|
|
3677
|
+
const bSameModel = UUIDsEqual(b.model.ID, currentModel.ID) ? 1 : 0;
|
|
3678
3678
|
return bSameModel - aSameModel;
|
|
3679
3679
|
});
|
|
3680
3680
|
}
|
|
3681
3681
|
else if (modelStrategy === 'PreferDifferentModel') {
|
|
3682
3682
|
// Sort to put different models first
|
|
3683
3683
|
candidates.sort((a, b) => {
|
|
3684
|
-
const aDiffModel = a.model.ID
|
|
3685
|
-
const bDiffModel = b.model.ID
|
|
3684
|
+
const aDiffModel = !UUIDsEqual(a.model.ID, currentModel.ID) ? 1 : 0;
|
|
3685
|
+
const bDiffModel = !UUIDsEqual(b.model.ID, currentModel.ID) ? 1 : 0;
|
|
3686
3686
|
return bDiffModel - aDiffModel;
|
|
3687
3687
|
});
|
|
3688
3688
|
}
|