@memberjunction/ai-prompts 2.118.0 → 2.119.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -17
- package/dist/AIPromptRunner.d.ts +17 -0
- package/dist/AIPromptRunner.d.ts.map +1 -1
- package/dist/AIPromptRunner.js +296 -222
- package/dist/AIPromptRunner.js.map +1 -1
- package/package.json +9 -9
package/dist/AIPromptRunner.js
CHANGED
|
@@ -770,222 +770,284 @@ class AIPromptRunner {
|
|
|
770
770
|
}
|
|
771
771
|
}
|
|
772
772
|
buildModelVendorCandidates(prompt, explicitModelId, configurationId, preferredVendorId, verbose) {
|
|
773
|
+
if (explicitModelId) {
|
|
774
|
+
return this.buildCandidatesForExplicitModel(explicitModelId, prompt, preferredVendorId);
|
|
775
|
+
}
|
|
776
|
+
if (prompt.SelectionStrategy === 'Specific') {
|
|
777
|
+
return this.buildCandidatesForSpecificStrategy(prompt, configurationId, verbose);
|
|
778
|
+
}
|
|
779
|
+
return this.buildCandidatesForGeneralSelection(prompt, configurationId, preferredVendorId, verbose);
|
|
780
|
+
}
|
|
781
|
+
buildCandidatesForExplicitModel(explicitModelId, prompt, preferredVendorId) {
|
|
782
|
+
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === explicitModelId);
|
|
783
|
+
if (!model || !model.IsActive) {
|
|
784
|
+
return [];
|
|
785
|
+
}
|
|
786
|
+
if (prompt.AIModelTypeID && model.AIModelTypeID !== prompt.AIModelTypeID) {
|
|
787
|
+
return [];
|
|
788
|
+
}
|
|
789
|
+
const candidates = this.createCandidatesForModel(model, 20000, 'explicit', preferredVendorId);
|
|
790
|
+
candidates.sort((a, b) => b.priority - a.priority);
|
|
791
|
+
return candidates;
|
|
792
|
+
}
|
|
793
|
+
buildCandidatesForSpecificStrategy(prompt, configurationId, verbose) {
|
|
794
|
+
const allPromptModels = aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID && (pm.Status === 'Active' || pm.Status === 'Preview'));
|
|
795
|
+
const promptModels = this.filterPromptModelsByConfiguration(allPromptModels, configurationId);
|
|
796
|
+
const sortedPromptModels = this.sortPromptModelsForSpecificStrategy(promptModels, configurationId);
|
|
797
|
+
const candidates = this.buildCandidatesFromPromptModels(sortedPromptModels);
|
|
798
|
+
if (candidates.length === 0) {
|
|
799
|
+
const configInfo = configurationId ? ` with configuration "${configurationId}"` : '';
|
|
800
|
+
throw new Error(`SelectionStrategy is 'Specific' but no valid AIPromptModel candidates found for prompt "${prompt.Name}"${configInfo}. ` +
|
|
801
|
+
`Please configure AIPromptModel records for this prompt.`);
|
|
802
|
+
}
|
|
803
|
+
if (verbose) {
|
|
804
|
+
(0, core_1.LogStatus)(`Using SelectionStrategy='Specific' with ${sortedPromptModels.length} AIPromptModel entries, generated ${candidates.length} candidates`);
|
|
805
|
+
}
|
|
806
|
+
return candidates;
|
|
807
|
+
}
|
|
808
|
+
buildCandidatesForGeneralSelection(prompt, configurationId, preferredVendorId, verbose) {
|
|
773
809
|
const preferredVendorName = preferredVendorId ?
|
|
774
810
|
aiengine_1.AIEngine.Instance.Vendors.find(v => v.ID === preferredVendorId)?.Name : undefined;
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
const preferredVendor = modelVendors.find(mv => mv.VendorID === preferredVendorId);
|
|
782
|
-
if (preferredVendor) {
|
|
783
|
-
modelCandidates.push({
|
|
784
|
-
model,
|
|
785
|
-
vendorId: preferredVendor.VendorID,
|
|
786
|
-
vendorName: preferredVendor.Vendor,
|
|
787
|
-
driverClass: preferredVendor.DriverClass || model.DriverClass,
|
|
788
|
-
apiName: preferredVendor.APIName || model.APIName,
|
|
789
|
-
supportsEffortLevel: preferredVendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
790
|
-
isPreferredVendor: true,
|
|
791
|
-
priority: basePriority + 1000,
|
|
792
|
-
source
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
for (const vendor of modelVendors) {
|
|
797
|
-
if (vendor.VendorID !== preferredVendorId) {
|
|
798
|
-
modelCandidates.push({
|
|
799
|
-
model,
|
|
800
|
-
vendorId: vendor.VendorID,
|
|
801
|
-
vendorName: vendor.Vendor,
|
|
802
|
-
driverClass: vendor.DriverClass || model.DriverClass,
|
|
803
|
-
apiName: vendor.APIName || model.APIName,
|
|
804
|
-
supportsEffortLevel: vendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
805
|
-
isPreferredVendor: false,
|
|
806
|
-
priority: basePriority + (vendor.Priority || 0),
|
|
807
|
-
source
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
if (modelCandidates.length === 0 && model.DriverClass) {
|
|
812
|
-
modelCandidates.push({
|
|
813
|
-
model,
|
|
814
|
-
driverClass: model.DriverClass,
|
|
815
|
-
apiName: model.APIName,
|
|
816
|
-
supportsEffortLevel: model.SupportsEffortLevel ?? false,
|
|
817
|
-
isPreferredVendor: false,
|
|
818
|
-
priority: basePriority,
|
|
819
|
-
source
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
if (promptModelPriority !== undefined) {
|
|
823
|
-
modelCandidates.forEach(c => c.priority += promptModelPriority * 10);
|
|
824
|
-
}
|
|
825
|
-
return modelCandidates;
|
|
826
|
-
};
|
|
827
|
-
const createSpecificCandidatesForModel = (model, promptModel, preferredVendorId) => {
|
|
828
|
-
const modelCandidates = [];
|
|
829
|
-
const basePriority = 10000 + (promptModel.Priority || 0) * 100;
|
|
830
|
-
const modelVendors = aiengine_1.AIEngine.Instance.ModelVendors
|
|
831
|
-
.filter(mv => mv.ModelID === model.ID && mv.Status === 'Active' && this.isInferenceProvider(mv));
|
|
832
|
-
const pmPreferredVendorId = promptModel.VendorID || preferredVendorId;
|
|
833
|
-
if (pmPreferredVendorId) {
|
|
834
|
-
const preferredVendor = modelVendors.find(mv => mv.VendorID === pmPreferredVendorId);
|
|
835
|
-
if (preferredVendor) {
|
|
836
|
-
modelCandidates.push({
|
|
837
|
-
model,
|
|
838
|
-
vendorId: preferredVendor.VendorID,
|
|
839
|
-
vendorName: preferredVendor.Vendor,
|
|
840
|
-
driverClass: preferredVendor.DriverClass || model.DriverClass,
|
|
841
|
-
apiName: preferredVendor.APIName || model.APIName,
|
|
842
|
-
supportsEffortLevel: preferredVendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
843
|
-
isPreferredVendor: true,
|
|
844
|
-
priority: basePriority + 1000,
|
|
845
|
-
source: 'prompt-model'
|
|
846
|
-
});
|
|
847
|
-
}
|
|
811
|
+
const promptModels = this.getPromptModelsForConfiguration(prompt, configurationId);
|
|
812
|
+
const candidates = [];
|
|
813
|
+
if (promptModels.length > 0) {
|
|
814
|
+
this.addPromptSpecificCandidates(candidates, promptModels, preferredVendorId);
|
|
815
|
+
if (configurationId) {
|
|
816
|
+
this.addConfigurationFallbackCandidates(candidates, prompt, configurationId, preferredVendorId, verbose);
|
|
848
817
|
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
this.addStrategyBasedCandidates(candidates, prompt, preferredVendorName);
|
|
821
|
+
}
|
|
822
|
+
candidates.sort((a, b) => b.priority - a.priority);
|
|
823
|
+
return candidates;
|
|
824
|
+
}
|
|
825
|
+
filterPromptModelsByConfiguration(allPromptModels, configurationId) {
|
|
826
|
+
if (configurationId) {
|
|
827
|
+
return allPromptModels.filter(pm => pm.ConfigurationID === configurationId || pm.ConfigurationID === null);
|
|
828
|
+
}
|
|
829
|
+
else {
|
|
830
|
+
return allPromptModels.filter(pm => pm.ConfigurationID === null);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
sortPromptModelsForSpecificStrategy(promptModels, configurationId) {
|
|
834
|
+
return promptModels.sort((a, b) => {
|
|
835
|
+
const aIsConfigMatch = configurationId && a.ConfigurationID === configurationId ? 1 : 0;
|
|
836
|
+
const bIsConfigMatch = configurationId && b.ConfigurationID === configurationId ? 1 : 0;
|
|
837
|
+
if (aIsConfigMatch !== bIsConfigMatch) {
|
|
838
|
+
return bIsConfigMatch - aIsConfigMatch;
|
|
839
|
+
}
|
|
840
|
+
return (b.Priority || 0) - (a.Priority || 0);
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
buildCandidatesFromPromptModels(promptModels) {
|
|
844
|
+
const candidates = [];
|
|
845
|
+
for (const pm of promptModels) {
|
|
846
|
+
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === pm.ModelID);
|
|
847
|
+
if (!model || !model.IsActive)
|
|
848
|
+
continue;
|
|
849
|
+
if (pm.VendorID) {
|
|
850
|
+
const candidate = this.createCandidateForSpecificVendor(model, pm);
|
|
851
|
+
if (candidate) {
|
|
852
|
+
candidates.push(candidate);
|
|
862
853
|
}
|
|
863
854
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
driverClass: model.DriverClass,
|
|
868
|
-
apiName: model.APIName,
|
|
869
|
-
supportsEffortLevel: model.SupportsEffortLevel ?? false,
|
|
870
|
-
isPreferredVendor: false,
|
|
871
|
-
priority: basePriority,
|
|
872
|
-
source: 'prompt-model'
|
|
873
|
-
});
|
|
855
|
+
else {
|
|
856
|
+
const vendorCandidates = this.createCandidatesForAllVendors(model);
|
|
857
|
+
candidates.push(...vendorCandidates);
|
|
874
858
|
}
|
|
875
|
-
|
|
859
|
+
}
|
|
860
|
+
return candidates;
|
|
861
|
+
}
|
|
862
|
+
createCandidateForSpecificVendor(model, promptModel) {
|
|
863
|
+
const modelVendor = aiengine_1.AIEngine.Instance.ModelVendors.find(mv => mv.ModelID === promptModel.ModelID &&
|
|
864
|
+
mv.VendorID === promptModel.VendorID &&
|
|
865
|
+
mv.Status === 'Active' &&
|
|
866
|
+
this.isInferenceProvider(mv));
|
|
867
|
+
if (!modelVendor)
|
|
868
|
+
return null;
|
|
869
|
+
return {
|
|
870
|
+
model,
|
|
871
|
+
vendorId: modelVendor.VendorID,
|
|
872
|
+
vendorName: modelVendor.Vendor,
|
|
873
|
+
driverClass: modelVendor.DriverClass || model.DriverClass,
|
|
874
|
+
apiName: modelVendor.APIName || model.APIName,
|
|
875
|
+
supportsEffortLevel: modelVendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
876
|
+
isPreferredVendor: false,
|
|
877
|
+
priority: 0,
|
|
878
|
+
source: 'prompt-model'
|
|
876
879
|
};
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
880
|
+
}
|
|
881
|
+
createCandidatesForAllVendors(model) {
|
|
882
|
+
const vendors = aiengine_1.AIEngine.Instance.ModelVendors
|
|
883
|
+
.filter(mv => mv.ModelID === model.ID &&
|
|
884
|
+
mv.Status === 'Active' &&
|
|
885
|
+
this.isInferenceProvider(mv))
|
|
886
|
+
.sort((a, b) => (b.Priority || 0) - (a.Priority || 0));
|
|
887
|
+
const candidates = [];
|
|
888
|
+
for (const vendor of vendors) {
|
|
889
|
+
candidates.push({
|
|
890
|
+
model,
|
|
891
|
+
vendorId: vendor.VendorID,
|
|
892
|
+
vendorName: vendor.Vendor,
|
|
893
|
+
driverClass: vendor.DriverClass || model.DriverClass,
|
|
894
|
+
apiName: vendor.APIName || model.APIName,
|
|
895
|
+
supportsEffortLevel: vendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
896
|
+
isPreferredVendor: false,
|
|
897
|
+
priority: 0,
|
|
898
|
+
source: 'prompt-model'
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
if (candidates.length === 0 && model.DriverClass) {
|
|
902
|
+
candidates.push({
|
|
903
|
+
model,
|
|
904
|
+
driverClass: model.DriverClass,
|
|
905
|
+
apiName: model.APIName,
|
|
906
|
+
supportsEffortLevel: model.SupportsEffortLevel ?? false,
|
|
907
|
+
isPreferredVendor: false,
|
|
908
|
+
priority: 0,
|
|
909
|
+
source: 'prompt-model'
|
|
910
|
+
});
|
|
887
911
|
}
|
|
888
|
-
|
|
912
|
+
return candidates;
|
|
913
|
+
}
|
|
914
|
+
getPromptModelsForConfiguration(prompt, configurationId) {
|
|
889
915
|
if (configurationId) {
|
|
890
|
-
promptModels = aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
916
|
+
const promptModels = aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
891
917
|
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
892
918
|
pm.ConfigurationID === configurationId);
|
|
893
919
|
if (promptModels.length === 0) {
|
|
894
920
|
(0, core_1.LogStatus)(`No models found for configuration "${configurationId}", falling back to default models`);
|
|
895
|
-
|
|
921
|
+
return aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
896
922
|
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
897
923
|
!pm.ConfigurationID);
|
|
898
924
|
}
|
|
925
|
+
return promptModels;
|
|
899
926
|
}
|
|
900
927
|
else {
|
|
901
|
-
|
|
928
|
+
return aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
902
929
|
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
903
930
|
!pm.ConfigurationID);
|
|
904
931
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
candidates.push(...modelCandidates);
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
if (candidates.length > 0) {
|
|
916
|
-
candidates.sort((a, b) => b.priority - a.priority);
|
|
917
|
-
if (verbose) {
|
|
918
|
-
(0, core_1.LogStatus)(`Using SelectionStrategy='Specific' with ${promptModels.length} AIPromptModel entries, generated ${candidates.length} candidates`);
|
|
919
|
-
}
|
|
920
|
-
return candidates;
|
|
921
|
-
}
|
|
922
|
-
if (verbose) {
|
|
923
|
-
(0, core_1.LogStatus)(`SelectionStrategy='Specific' specified but no usable candidates from AIPromptModel entries, falling back to general selection`);
|
|
932
|
+
}
|
|
933
|
+
addPromptSpecificCandidates(candidates, promptModels, preferredVendorId) {
|
|
934
|
+
for (const pm of promptModels) {
|
|
935
|
+
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === pm.ModelID);
|
|
936
|
+
if (model && model.IsActive) {
|
|
937
|
+
const modelCandidates = this.createCandidatesForModel(model, 5000, 'prompt-model', preferredVendorId, pm.Priority);
|
|
938
|
+
candidates.push(...modelCandidates);
|
|
924
939
|
}
|
|
925
940
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
if (nullConfigModels.length > 0 && verbose) {
|
|
940
|
-
(0, core_1.LogStatus)(`Adding ${nullConfigModels.length} NULL configuration models as fallback candidates`);
|
|
941
|
-
}
|
|
942
|
-
for (const pm of nullConfigModels) {
|
|
943
|
-
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === pm.ModelID);
|
|
944
|
-
if (model && model.IsActive) {
|
|
945
|
-
const modelCandidates = createCandidatesForModel(model, 2000, 'prompt-model', pm.Priority);
|
|
946
|
-
candidates.push(...modelCandidates);
|
|
947
|
-
}
|
|
948
|
-
}
|
|
941
|
+
}
|
|
942
|
+
addConfigurationFallbackCandidates(candidates, prompt, configurationId, preferredVendorId, verbose) {
|
|
943
|
+
const nullConfigModels = aiengine_1.AIEngine.Instance.PromptModels.filter(pm => pm.PromptID === prompt.ID &&
|
|
944
|
+
(pm.Status === 'Active' || pm.Status === 'Preview') &&
|
|
945
|
+
!pm.ConfigurationID);
|
|
946
|
+
if (nullConfigModels.length > 0 && verbose) {
|
|
947
|
+
(0, core_1.LogStatus)(`Adding ${nullConfigModels.length} NULL configuration models as fallback candidates`);
|
|
948
|
+
}
|
|
949
|
+
for (const pm of nullConfigModels) {
|
|
950
|
+
const model = aiengine_1.AIEngine.Instance.Models.find(m => m.ID === pm.ModelID);
|
|
951
|
+
if (model && model.IsActive) {
|
|
952
|
+
const modelCandidates = this.createCandidatesForModel(model, 2000, 'prompt-model', preferredVendorId, pm.Priority);
|
|
953
|
+
candidates.push(...modelCandidates);
|
|
949
954
|
}
|
|
950
955
|
}
|
|
956
|
+
}
|
|
957
|
+
addStrategyBasedCandidates(candidates, prompt, preferredVendorName) {
|
|
958
|
+
let modelPool = this.getModelPoolForStrategy(prompt, preferredVendorName);
|
|
959
|
+
modelPool = this.sortModelPoolByStrategy(modelPool, prompt);
|
|
960
|
+
modelPool.forEach((model, index) => {
|
|
961
|
+
const basePriority = 1000 - index * 10;
|
|
962
|
+
const source = prompt.SelectionStrategy === 'ByPower' ? 'power-rank' : 'model-type';
|
|
963
|
+
candidates.push(...this.createCandidatesForModel(model, basePriority, source));
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
getModelPoolForStrategy(prompt, preferredVendorName) {
|
|
967
|
+
return aiengine_1.AIEngine.Instance.Models.filter(m => m.IsActive &&
|
|
968
|
+
(!prompt.AIModelTypeID || m.AIModelTypeID === prompt.AIModelTypeID) &&
|
|
969
|
+
(!preferredVendorName ||
|
|
970
|
+
aiengine_1.AIEngine.Instance.ModelVendors.some(mv => mv.ModelID === m.ID &&
|
|
971
|
+
mv.Status === 'Active' &&
|
|
972
|
+
mv.Vendor === preferredVendorName &&
|
|
973
|
+
this.isInferenceProvider(mv))));
|
|
974
|
+
}
|
|
975
|
+
sortModelPoolByStrategy(modelPool, prompt) {
|
|
976
|
+
if (prompt.SelectionStrategy === 'ByPower') {
|
|
977
|
+
return this.sortByPowerPreference(modelPool, prompt.PowerPreference);
|
|
978
|
+
}
|
|
951
979
|
else {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
(
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
980
|
+
const minPowerRank = prompt.MinPowerRank || 0;
|
|
981
|
+
return modelPool
|
|
982
|
+
.filter(m => m.PowerRank >= minPowerRank)
|
|
983
|
+
.sort((a, b) => b.PowerRank - a.PowerRank);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
sortByPowerPreference(modelPool, powerPreference) {
|
|
987
|
+
const pool = [...modelPool];
|
|
988
|
+
switch (powerPreference) {
|
|
989
|
+
case 'Highest':
|
|
990
|
+
return pool.sort((a, b) => b.PowerRank - a.PowerRank);
|
|
991
|
+
case 'Lowest':
|
|
992
|
+
return pool.sort((a, b) => a.PowerRank - b.PowerRank);
|
|
993
|
+
case 'Balanced':
|
|
994
|
+
const avgPower = pool.reduce((sum, m) => sum + m.PowerRank, 0) / pool.length;
|
|
995
|
+
return pool.sort((a, b) => Math.abs(a.PowerRank - avgPower) - Math.abs(b.PowerRank - avgPower));
|
|
996
|
+
default:
|
|
997
|
+
return pool.sort((a, b) => b.PowerRank - a.PowerRank);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
createCandidatesForModel(model, basePriority, source, preferredVendorId, promptModelPriority) {
|
|
1001
|
+
const modelCandidates = [];
|
|
1002
|
+
const modelVendors = aiengine_1.AIEngine.Instance.ModelVendors
|
|
1003
|
+
.filter(mv => mv.ModelID === model.ID && mv.Status === 'Active' && this.isInferenceProvider(mv))
|
|
1004
|
+
.sort((a, b) => b.Priority - a.Priority);
|
|
1005
|
+
if (preferredVendorId) {
|
|
1006
|
+
const preferredVendor = modelVendors.find(mv => mv.VendorID === preferredVendorId);
|
|
1007
|
+
if (preferredVendor) {
|
|
1008
|
+
modelCandidates.push({
|
|
1009
|
+
model,
|
|
1010
|
+
vendorId: preferredVendor.VendorID,
|
|
1011
|
+
vendorName: preferredVendor.Vendor,
|
|
1012
|
+
driverClass: preferredVendor.DriverClass || model.DriverClass,
|
|
1013
|
+
apiName: preferredVendor.APIName || model.APIName,
|
|
1014
|
+
supportsEffortLevel: preferredVendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
1015
|
+
isPreferredVendor: true,
|
|
1016
|
+
priority: basePriority + 1000,
|
|
1017
|
+
source
|
|
1018
|
+
});
|
|
981
1019
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1020
|
+
}
|
|
1021
|
+
for (const vendor of modelVendors) {
|
|
1022
|
+
if (vendor.VendorID !== preferredVendorId) {
|
|
1023
|
+
modelCandidates.push({
|
|
1024
|
+
model,
|
|
1025
|
+
vendorId: vendor.VendorID,
|
|
1026
|
+
vendorName: vendor.Vendor,
|
|
1027
|
+
driverClass: vendor.DriverClass || model.DriverClass,
|
|
1028
|
+
apiName: vendor.APIName || model.APIName,
|
|
1029
|
+
supportsEffortLevel: vendor.SupportsEffortLevel ?? model.SupportsEffortLevel ?? false,
|
|
1030
|
+
isPreferredVendor: false,
|
|
1031
|
+
priority: basePriority + (vendor.Priority || 0),
|
|
1032
|
+
source
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
if (modelCandidates.length === 0 && model.DriverClass) {
|
|
1037
|
+
modelCandidates.push({
|
|
1038
|
+
model,
|
|
1039
|
+
driverClass: model.DriverClass,
|
|
1040
|
+
apiName: model.APIName,
|
|
1041
|
+
supportsEffortLevel: model.SupportsEffortLevel ?? false,
|
|
1042
|
+
isPreferredVendor: false,
|
|
1043
|
+
priority: basePriority,
|
|
1044
|
+
source
|
|
985
1045
|
});
|
|
986
1046
|
}
|
|
987
|
-
|
|
988
|
-
|
|
1047
|
+
if (promptModelPriority !== undefined) {
|
|
1048
|
+
modelCandidates.forEach(c => c.priority += promptModelPriority * 10);
|
|
1049
|
+
}
|
|
1050
|
+
return modelCandidates;
|
|
989
1051
|
}
|
|
990
1052
|
createSelectionInfo(data) {
|
|
991
1053
|
const info = new ai_core_plus_1.AIModelSelectionInfo();
|
|
@@ -1282,39 +1344,33 @@ class AIPromptRunner {
|
|
|
1282
1344
|
}
|
|
1283
1345
|
async executeModelWithFailover(model, renderedPrompt, prompt, params, vendorId, conversationMessages, templateMessageRole = 'system', cancellationToken, allCandidates, promptRun, vendorDriverClass, vendorApiName, vendorSupportsEffortLevel) {
|
|
1284
1346
|
const failoverConfig = this.getFailoverConfiguration(prompt);
|
|
1285
|
-
if (failoverConfig.strategy === 'None') {
|
|
1347
|
+
if (!allCandidates || allCandidates.length === 0 || failoverConfig.strategy === 'None') {
|
|
1286
1348
|
return this.executeModel(model, renderedPrompt, prompt, params, vendorId, conversationMessages, templateMessageRole, cancellationToken, vendorDriverClass, vendorApiName, vendorSupportsEffortLevel);
|
|
1287
1349
|
}
|
|
1288
1350
|
const failoverAttempts = [];
|
|
1289
1351
|
let lastError = null;
|
|
1290
|
-
let
|
|
1291
|
-
|
|
1292
|
-
let attemptNumber = 0;
|
|
1293
|
-
if (!allCandidates || allCandidates.length === 0) {
|
|
1294
|
-
allCandidates = await this.buildFailoverCandidates(prompt);
|
|
1295
|
-
}
|
|
1296
|
-
while (attemptNumber <= failoverConfig.maxAttempts) {
|
|
1297
|
-
attemptNumber++;
|
|
1352
|
+
for (let i = 0; i < allCandidates.length; i++) {
|
|
1353
|
+
const candidate = allCandidates[i];
|
|
1298
1354
|
const attemptStartTime = Date.now();
|
|
1299
1355
|
try {
|
|
1300
|
-
if (
|
|
1301
|
-
const vendorName =
|
|
1302
|
-
? aiengine_1.AIEngine.Instance.Vendors.find(v => v.ID === currentVendorId)?.Name || 'Unknown'
|
|
1303
|
-
: 'default';
|
|
1356
|
+
if (i > 0) {
|
|
1357
|
+
const vendorName = candidate.vendorName || 'default';
|
|
1304
1358
|
(0, core_1.LogStatusEx)({
|
|
1305
|
-
message: `🔄
|
|
1359
|
+
message: `🔄 Trying candidate ${i + 1}/${allCandidates.length}: ${candidate.model.Name} via ${vendorName}`,
|
|
1306
1360
|
category: 'AI',
|
|
1307
1361
|
additionalArgs: [{
|
|
1308
1362
|
promptId: prompt.ID,
|
|
1309
|
-
modelId:
|
|
1310
|
-
|
|
1311
|
-
|
|
1363
|
+
modelId: candidate.model.ID,
|
|
1364
|
+
model: candidate.model.Name,
|
|
1365
|
+
vendorId: candidate.vendorId,
|
|
1366
|
+
vendor: candidate.vendorName,
|
|
1367
|
+
attemptNumber: i + 1
|
|
1312
1368
|
}]
|
|
1313
1369
|
});
|
|
1314
1370
|
}
|
|
1315
|
-
const result = await this.executeModel(
|
|
1371
|
+
const result = await this.executeModel(candidate.model, renderedPrompt, prompt, params, candidate.vendorId || null, conversationMessages, templateMessageRole, cancellationToken, candidate.driverClass, candidate.apiName, candidate.supportsEffortLevel);
|
|
1316
1372
|
if (failoverAttempts.length > 0 && promptRun) {
|
|
1317
|
-
this.updatePromptRunWithFailoverSuccess(promptRun, failoverAttempts,
|
|
1373
|
+
this.updatePromptRunWithFailoverSuccess(promptRun, failoverAttempts, candidate.model, candidate.vendorId || null);
|
|
1318
1374
|
}
|
|
1319
1375
|
return result;
|
|
1320
1376
|
}
|
|
@@ -1323,34 +1379,39 @@ class AIPromptRunner {
|
|
|
1323
1379
|
lastError = error;
|
|
1324
1380
|
const errorAnalysis = ai_1.ErrorAnalyzer.analyzeError(lastError);
|
|
1325
1381
|
const failoverAttempt = {
|
|
1326
|
-
attemptNumber,
|
|
1327
|
-
modelId:
|
|
1328
|
-
vendorId:
|
|
1382
|
+
attemptNumber: i + 1,
|
|
1383
|
+
modelId: candidate.model.ID,
|
|
1384
|
+
vendorId: candidate.vendorId,
|
|
1329
1385
|
error: lastError,
|
|
1330
1386
|
errorType: errorAnalysis.errorType,
|
|
1331
1387
|
duration: attemptDuration,
|
|
1332
1388
|
timestamp: new Date()
|
|
1333
1389
|
};
|
|
1334
1390
|
failoverAttempts.push(failoverAttempt);
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
if (shouldContinueRateLimit) {
|
|
1338
|
-
continue;
|
|
1391
|
+
if (errorAnalysis.errorType === 'Authentication') {
|
|
1392
|
+
allCandidates = this.filterAuthenticationFailedVendor(errorAnalysis.errorType, candidate.vendorId, allCandidates);
|
|
1339
1393
|
}
|
|
1340
|
-
const
|
|
1341
|
-
if (
|
|
1394
|
+
const isLastCandidate = i === allCandidates.length - 1;
|
|
1395
|
+
if (errorAnalysis.severity === 'Fatal') {
|
|
1342
1396
|
this.logFailoverAttempt(prompt.ID, failoverAttempt, false);
|
|
1343
1397
|
break;
|
|
1344
1398
|
}
|
|
1345
|
-
|
|
1346
|
-
|
|
1399
|
+
if (errorAnalysis.errorType === 'InvalidRequest') {
|
|
1400
|
+
this.logFailoverAttempt(prompt.ID, failoverAttempt, false);
|
|
1401
|
+
break;
|
|
1402
|
+
}
|
|
1403
|
+
if (failoverConfig.errorScope && failoverConfig.errorScope !== 'All') {
|
|
1404
|
+
const matchesScope = this.errorMatchesScope(errorAnalysis.errorType, failoverConfig.errorScope);
|
|
1405
|
+
if (!matchesScope) {
|
|
1406
|
+
this.logFailoverAttempt(prompt.ID, failoverAttempt, false);
|
|
1407
|
+
break;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
if (isLastCandidate) {
|
|
1411
|
+
this.logFailoverAttempt(prompt.ID, failoverAttempt, false);
|
|
1347
1412
|
break;
|
|
1348
1413
|
}
|
|
1349
|
-
|
|
1350
|
-
currentVendorId = transitionResult.vendorId;
|
|
1351
|
-
vendorDriverClass = transitionResult.driverClass;
|
|
1352
|
-
vendorApiName = transitionResult.apiName;
|
|
1353
|
-
vendorSupportsEffortLevel = transitionResult.supportsEffortLevel;
|
|
1414
|
+
this.logFailoverAttempt(prompt.ID, failoverAttempt, true);
|
|
1354
1415
|
}
|
|
1355
1416
|
}
|
|
1356
1417
|
if (promptRun && failoverAttempts.length > 0) {
|
|
@@ -2420,6 +2481,19 @@ class AIPromptRunner {
|
|
|
2420
2481
|
return true;
|
|
2421
2482
|
}
|
|
2422
2483
|
}
|
|
2484
|
+
errorMatchesScope(errorType, scope) {
|
|
2485
|
+
switch (scope) {
|
|
2486
|
+
case 'NetworkOnly':
|
|
2487
|
+
return errorType === 'NetworkError';
|
|
2488
|
+
case 'RateLimitOnly':
|
|
2489
|
+
return errorType === 'RateLimit';
|
|
2490
|
+
case 'ServiceErrorOnly':
|
|
2491
|
+
return errorType === 'ServiceUnavailable' || errorType === 'InternalServerError';
|
|
2492
|
+
case 'All':
|
|
2493
|
+
default:
|
|
2494
|
+
return true;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2423
2497
|
calculateFailoverDelay(attemptNumber, baseDelaySeconds) {
|
|
2424
2498
|
const exponentialDelay = baseDelaySeconds * Math.pow(2, attemptNumber - 1);
|
|
2425
2499
|
const jitter = exponentialDelay * 0.25 * Math.random();
|