Sort the Alibaba Cloud model lists by what a model is made for

This commit is contained in:
Thorsten Sommer 2026-09-19 15:45:06 +02:00
parent 44ae33b506
commit fb3dee005c
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
4 changed files with 47 additions and 65 deletions

View File

@ -6547,9 +6547,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T1356621346"] = "Cr
-- Failed to validate the selected tokenizer. Please try again.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T1384494471"] = "Failed to validate the selected tokenizer. Please try again."
-- Please enter an embedding model name.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T1661085403"] = "Please enter an embedding model name."
-- Hostname
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T1727440780"] = "Hostname"
@ -6604,9 +6601,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2810182573"] = "No
-- Instance Name
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2842060373"] = "Instance Name"
-- Currently, we cannot query the embedding models for the selected provider and/or host. Therefore, please enter the model name manually.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T290547799"] = "Currently, we cannot query the embedding models for the selected provider and/or host. Therefore, please enter the model name manually."
-- Token limit
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T2961294165"] = "Token limit"
@ -6616,6 +6610,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T3316544737"] = "Pl
-- Show Expert Settings
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T3361153305"] = "Show Expert Settings"
-- None of the models on this server is one we recognize as an embedding model, so all of them are listed. Please pick the one you run for embeddings.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T3363221762"] = "None of the models on this server is one we recognize as an embedding model, so all of them are listed. Please pick the one you run for embeddings."
-- This server does not offer the selected model right now. It stays selected, so the documents you already prepared keep working. Choosing another model means every document of the data sources behind this provider is prepared again.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T3571276758"] = "This server does not offer the selected model right now. It stays selected, so the documents you already prepared keep working. Choosing another model means every document of the data sources behind this provider is prepared again."
-- How many chunks are sent to the embedding provider at once. The default is 1.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::EMBEDDINGPROVIDERDIALOG::T3780233303"] = "How many chunks are sent to the embedding provider at once. The default is 1."
@ -8716,9 +8716,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T1324664716"] =
-- Create account
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T1356621346"] = "Create account"
-- Currently, we cannot query the transcription models for the selected provider and/or host. Therefore, please enter the model name manually.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T1381635232"] = "Currently, we cannot query the transcription models for the selected provider and/or host. Therefore, please enter the model name manually."
-- Hostname
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T1727440780"] = "Hostname"
@ -8752,9 +8749,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T2842060373"] =
-- Hugging Face transcribes audio through a few of its inference providers only, which is why this list is shorter than the one for chatting.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T3397943774"] = "Hugging Face transcribes audio through a few of its inference providers only, which is why this list is shorter than the one for chatting."
-- Please enter a transcription model name.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T3703662664"] = "Please enter a transcription model name."
-- This host uses the model configured at the provider level. No model selection is available.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T3783329915"] = "This host uses the model configured at the provider level. No model selection is available."

View File

@ -9,9 +9,10 @@ namespace AIStudio.Models.Alibaba;
/// </summary>
/// <remarks>
/// The previous rules answered for these with the Model Studio default and told them they call
/// functions. The prefix is Alibaba's own: the app filters the catalog by "text-embedding-" to find
/// them, which is also why the rule may be written that broadly -- bound to this provider, it can
/// only ever meet the models Alibaba names that way.
/// functions. The prefix is Alibaba's own, and the rule may be written that broadly because it is
/// bound to this provider: it can only ever meet the models Alibaba names that way. The provider
/// carried the same prefix as a filter of its own until it started asking here, so this is now the
/// only place which says what those names mean.
/// </remarks>
public sealed class ModelStudioEmbeddingFamily : ModelFamily
{
@ -19,7 +20,7 @@ public sealed class ModelStudioEmbeddingFamily : ModelFamily
public override ModelVendor Vendor => ModelVendor.ALIBABA;
/// <inheritdoc />
public override ModelSource Source => new("https://www.alibabacloud.com/help/en/model-studio/embedding", new DateOnly(2026, 9, 11), "Provider/AlibabaCloud/ProviderAlibabaCloud.cs adds these in GetEmbeddingModels and filters the catalog by the prefix \"text-embedding-\".");
public override ModelSource Source => new("https://www.alibabacloud.com/help/en/model-studio/embedding", new DateOnly(2026, 9, 11), "Provider/AlibabaCloud/ProviderAlibabaCloud.cs used to add these in GetEmbeddingModels and to filter the catalog by the prefix \"text-embedding-\"; it asks this rule instead.");
/// <inheritdoc />
protected override void Declare(ModelFamilyBuilder builder) =>

View File

@ -76,40 +76,8 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C
/// <inheritdoc />
public override async Task<ModelLoadResult> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default)
{
var additionalModels = new[]
{
new Model("qwq-plus", "QwQ plus"), // reasoning model
new Model("qwen-max-latest", "Qwen-Max (Latest)"),
new Model("qwen-plus-latest", "Qwen-Plus (Latest)"),
new Model("qwen-turbo-latest", "Qwen-Turbo (Latest)"),
new Model("qvq-max", "QVQ Max"), // visual reasoning model
new Model("qvq-max-latest", "QVQ Max (Latest)"), // visual reasoning model
new Model("qwen-vl-max", "Qwen-VL Max"), // text generation model that can understand and process images
new Model("qwen-vl-plus", "Qwen-VL Plus"), // text generation model that can understand and process images
new Model("qwen-mt-plus", "Qwen-MT Plus"), // machine translation
new Model("qwen-mt-turbo", "Qwen-MT Turbo"), // machine translation
//Open source
new Model("qwen2.5-14b-instruct-1m", "Qwen2.5 14b 1m context"),
new Model("qwen2.5-7b-instruct-1m", "Qwen2.5 7b 1m context"),
new Model("qwen2.5-72b-instruct", "Qwen2.5 72b"),
new Model("qwen2.5-32b-instruct", "Qwen2.5 32b"),
new Model("qwen2.5-14b-instruct", "Qwen2.5 14b"),
new Model("qwen2.5-7b-instruct", "Qwen2.5 7b"),
new Model("qwen2.5-omni-7b", "Qwen2.5-Omni 7b"), // omni-modal understanding and generation model
new Model("qwen2.5-vl-72b-instruct", "Qwen2.5-VL 72b"),
new Model("qwen2.5-vl-32b-instruct", "Qwen2.5-VL 32b"),
new Model("qwen2.5-vl-7b-instruct", "Qwen2.5-VL 7b"),
new Model("qwen2.5-vl-3b-instruct", "Qwen2.5-VL 3b"),
};
var result = await this.LoadModels(["q"], SecretStoreType.LLM_PROVIDER, apiKeyProvisional, token);
return result with
{
// The API is the authority: when it reports a model we also keep as a fallback above,
// its entry comes first and the fallback is dropped.
Models = [..result.Models.Concat(additionalModels).DistinctBy(x => x.Id).OrderBy(x => x.Id)]
};
var result = await this.LoadModels(SecretStoreType.LLM_PROVIDER, apiKeyProvisional, token);
return result with { Models = [..result.Models.Where(model => model.IsChatModel(this.Provider)).OrderBy(x => x.Id)] };
}
/// <inheritdoc />
@ -121,19 +89,8 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C
/// <inheritdoc />
public override async Task<ModelLoadResult> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default)
{
var additionalModels = new[]
{
new Model("text-embedding-v3", "text-embedding-v3"),
};
var result = await this.LoadModels(["text-embedding-"], SecretStoreType.EMBEDDING_PROVIDER, apiKeyProvisional, token);
return result with
{
// The API is the authority: when it reports a model we also keep as a fallback above,
// its entry comes first and the fallback is dropped.
Models = [..result.Models.Concat(additionalModels).DistinctBy(x => x.Id).OrderBy(x => x.Id)]
};
var result = await this.LoadModels(SecretStoreType.EMBEDDING_PROVIDER, apiKeyProvisional, token);
return result with { Models = [..result.Models.Where(model => model.IsEmbeddingModel(this.Provider)).OrderBy(x => x.Id)] };
}
#region Overrides of BaseProvider
@ -148,12 +105,23 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C
#endregion
private Task<ModelLoadResult> LoadModels(string[] prefixes, SecretStoreType storeType, string? apiKeyProvisional, CancellationToken token)
/// <summary>
/// Reads Model Studio's catalog, whole.
/// </summary>
/// <remarks>
/// It used to be read through a prefix per list -- a single "q" for the models to talk to, and
/// "text-embedding-" for the ones which answer in vectors. Neither survived what Model Studio
/// became: the letter also brings qwen-image, qwen-tts, qwen3-asr and qwen-vl-ocr into the chat
/// list, while it locks out DeepSeek, Kimi, GLM and MiniMax, which Alibaba serves through this
/// very endpoint. A name has never been a statement about what a model is for; the callers ask
/// the registry instead.
/// </remarks>
private Task<ModelLoadResult> LoadModels(SecretStoreType storeType, string? apiKeyProvisional, CancellationToken token)
{
return this.LoadModelsResponse<ModelsResponse>(
storeType,
"models",
modelResponse => modelResponse.Data.Where(model => prefixes.Any(prefix => model.Id.StartsWith(prefix, StringComparison.InvariantCulture))),
modelResponse => modelResponse.Data,
apiKeyProvisional, token: token);
}
}

View File

@ -39,6 +39,11 @@ public static class ModelKindCorpus
// model is for is said by the word which says it, not by the family it was built from.
new(MISTRAL, "codestral-embed", EMBEDDING),
// Alibaba names its own by the prefix the provider used to filter the catalog by. The rule
// says it now, so the prefix is free to go:
new(ALIBABA_CLOUD, "text-embedding-v3", EMBEDDING),
new(ALIBABA_CLOUD, "text-embedding-v4", EMBEDDING),
//
// What a local Ollama installation serves, taken off its models endpoint rather than
// written from memory. The last two are the ones worth having: neither name carries the
@ -85,6 +90,8 @@ public static class ModelKindCorpus
new(GOOGLE, "gemini-3-pro-image", IMAGE_GENERATION),
new(GOOGLE, "imagen-4.0-generate-001", IMAGE_GENERATION, AnsweredTodayAs: CHAT, Reason: "The markers never knew the name; the family ported in the Google step states it. Nobody noticed because the Google provider shows only names beginning with gemini."),
new(ALIBABA_CLOUD, "qwen-image-edit", IMAGE_GENERATION),
];
/// <summary>
@ -196,6 +203,7 @@ public static class ModelKindCorpus
private static readonly ModelKindExample[] OCR_ENTRIES =
[
new(MISTRAL, "mistral-ocr-latest", OCR),
new(ALIBABA_CLOUD, "qwen-vl-ocr", OCR),
];
/// <summary>
@ -247,6 +255,17 @@ public static class ModelKindCorpus
// is one letter longer than it. A name part is what keeps the two apart:
new(SELF_HOSTED, "mistral-7b-instruct", CHAT),
//
// What somebody actually comes to Alibaba Cloud for, held here because the provider is
// about to stop keeping its chat list by the letter every one of these begins with. The
// last one translates rather than converses, and it does so through the chat completion
// API like the others, so this is where it belongs.
//
new(ALIBABA_CLOUD, "qwen-max-latest", CHAT),
new(ALIBABA_CLOUD, "qwq-plus", CHAT),
new(ALIBABA_CLOUD, "qvq-max", CHAT),
new(ALIBABA_CLOUD, "qwen-mt-turbo", CHAT),
//
// Three which were questioned while testing and stay all the same. Grok Build is the coding
// model behind the xAI CLI and answers like any other Grok. The Groq compound systems are