fix(models): store provider custom models by provider scope

This commit is contained in:
nguyenha935
2026-06-20 15:19:22 +07:00
committed by decolua
parent 8efacc1147
commit 707a91555d
6 changed files with 282 additions and 118 deletions
+20 -6
View File
@@ -181,26 +181,41 @@ export default function ModelSelectModal({
name: aliasName,
value: fullModel,
}));
const customRegisteredModels = customModels
.filter((m) => m.providerAlias === alias)
.map((m) => ({
id: m.id,
name: m.name || m.id,
value: `${alias}/${m.id}`,
kind: getModelKind(m),
isCustom: true,
}));
// For typed kinds, only include hardcoded typed models (aliases are typically LLM-only and lack type info)
let combined = aliasModels;
if (kindFilter && TYPED_KINDS.has(kindFilter)) {
combined = getModelsByProviderId(providerId)
const registeredTyped = customRegisteredModels.filter((m) => getModelKind(m) === kindFilter);
combined = [
...registeredTyped,
...getModelsByProviderId(providerId)
.filter((m) => getModelKind(m) === kindFilter)
.map((m) => ({ id: m.id, name: m.name, value: `${alias}/${m.id}`, kind: getModelKind(m) }));
.map((m) => ({ id: m.id, name: m.name, value: `${alias}/${m.id}`, kind: getModelKind(m) }))
.filter((m) => !registeredTyped.some((registered) => registered.value === m.value)),
];
// Fallback: provider-as-model when no hardcoded models match (tts/image/webFetch only)
if (combined.length === 0 && ALLOW_PROVIDER_FALLBACK_KINDS.has(kindFilter)) {
const supports = (providerInfo.serviceKinds || ["llm"]).includes(kindFilter);
if (supports) combined = [{ id: providerId, name: providerInfo.name, value: alias }];
}
} else {
// LLM/null kind: merge hardcoded models (e.g. mimo-free → mimo-auto) with aliases
const seen = new Set(aliasModels.map((m) => m.value));
// LLM/null kind: merge hardcoded models (e.g. mimo-free → mimo-auto) with user-added models
const registeredLlms = customRegisteredModels.filter((m) => !getModelKind(m) || getModelKind(m) === "llm");
const seen = new Set([...aliasModels, ...registeredLlms].map((m) => m.value));
const hardcoded = getModelsByProviderId(providerId)
.filter((m) => !getModelKind(m) || getModelKind(m) === "llm")
.map((m) => ({ id: m.id, name: m.name, value: `${alias}/${m.id}`, kind: getModelKind(m) }))
.filter((m) => !seen.has(m.value));
combined = [...aliasModels, ...hardcoded];
combined = [...registeredLlms, ...aliasModels.filter((m) => !registeredLlms.some((registered) => registered.value === m.value)), ...hardcoded];
}
if (combined.length > 0) {
@@ -551,4 +566,3 @@ ModelSelectModal.propTypes = {
addedModelValues: PropTypes.arrayOf(PropTypes.string),
closeOnSelect: PropTypes.bool,
};
+54
View File
@@ -0,0 +1,54 @@
function modelType(model) {
return model?.kind || model?.type || "llm";
}
export function getProviderCustomModelRows({
customModels = [],
modelAliases = {},
providerAlias,
builtInModels = [],
type = "llm",
includeLegacyAliases = true,
}) {
const builtInIds = new Set(builtInModels.map((model) => model.id));
const seenFullModels = new Set();
const rows = [];
for (const model of customModels) {
if (!model?.id || model.providerAlias !== providerAlias) continue;
const rowType = modelType(model);
if (type && rowType !== type) continue;
if (builtInIds.has(model.id)) continue;
const fullModel = `${providerAlias}/${model.id}`;
if (seenFullModels.has(fullModel)) continue;
seenFullModels.add(fullModel);
rows.push({
id: model.id,
name: model.name || model.id,
fullModel,
source: "custom",
type: rowType,
});
}
if (!includeLegacyAliases) return rows;
const prefix = `${providerAlias}/`;
for (const [alias, fullModel] of Object.entries(modelAliases || {})) {
if (typeof fullModel !== "string" || !fullModel.startsWith(prefix)) continue;
const id = fullModel.slice(prefix.length);
if (!id || builtInIds.has(id) || seenFullModels.has(fullModel)) continue;
seenFullModels.add(fullModel);
rows.push({
id,
alias,
fullModel,
source: "legacyAlias",
type: type || "llm",
});
}
return rows;
}