AI-Studio/app/MindWork AI Studio/Settings/ProviderExtensions.OpenSource.cs

618 lines
23 KiB
C#
Raw Normal View History

using AIStudio.Provider;
2025-05-11 10:51:35 +00:00
namespace AIStudio.Settings;
public static partial class ProviderExtensions
2025-05-11 10:51:35 +00:00
{
2025-12-30 17:30:32 +00:00
private static List<Capability> GetModelCapabilitiesOpenSource(Model model)
2025-05-11 10:51:35 +00:00
{
var modelName = model.Id.ToLowerInvariant().AsSpan();
//
// Checking for names in the case of open source models is a hard task.
// Let's assume we want to check for the llama 3.1 405b model.
//
// Here is a not complete list of how providers name this model:
// - Fireworks: accounts/fireworks/models/llama-v3p1-405b-instruct
// - Hugging Face -> Nebius AI Studio: meta-llama/Meta-Llama-3.1-405B-Instruct
// - Groq: llama-3.1-405b-instruct
// - LM Studio: llama-3.1-405b-instruct
// - Helmholtz Blablador: 1 - Llama3 405 the best general model
// - GWDG: Llama 3.1 405B Instruct
//
//
// Meta llama models:
//
if (modelName.IndexOf("llama") is not -1)
{
if (modelName.IndexOf("llama4") is not -1 ||
modelName.IndexOf("llama 4") is not -1 ||
modelName.IndexOf("llama-4") is not -1 ||
modelName.IndexOf("llama-v4") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
2025-09-03 08:08:04 +00:00
Capability.CHAT_COMPLETION_API,
2025-05-11 10:51:35 +00:00
];
// The old vision models cannot do function calling:
if (modelName.IndexOf("vision") is not -1)
2025-09-03 08:08:04 +00:00
return [
Capability.TEXT_INPUT,
Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
//
// All models >= 3.1 are able to do function calling:
//
if (modelName.IndexOf("llama3.") is not -1 ||
modelName.IndexOf("llama 3.") is not -1 ||
modelName.IndexOf("llama-3.") is not -1 ||
modelName.IndexOf("llama-v3p") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
2025-09-03 08:08:04 +00:00
Capability.CHAT_COMPLETION_API,
2025-05-11 10:51:35 +00:00
];
// All other llama models can only do text input and output:
2025-09-03 08:08:04 +00:00
return [
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
}
//
// Meta Muse models. They need their own block because their names do not
// contain "llama". Muse Glimmer always reasons: its chat template opens the
// thinking channel unconditionally, only the reasoning strength can be lowered.
//
if (modelName.IndexOf("muse-glimmer") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
//
// DeepSeek models:
//
if (modelName.IndexOf("deepseek") is not -1)
{
if ((modelName.IndexOf("deepseek-v4-flash") is not -1 ||
modelName.IndexOf("deepseek-v4-pro") is not -1) &&
modelName.IndexOf("-base") is -1)
return
[
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.REASONING_BY_DEFAULT, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
if(modelName.IndexOf("deepseek-r1") is not -1 ||
modelName.IndexOf("deepseek r1") is not -1)
2025-09-03 08:08:04 +00:00
return [
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
2025-09-03 08:08:04 +00:00
return [
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
}
//
// Qwen models:
//
if (modelName.IndexOf("qwen") is not -1 || modelName.IndexOf("qwq") is not -1)
{
if (modelName.IndexOf("qwq") is not -1)
2025-09-03 08:08:04 +00:00
return [
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING,
Capability.CHAT_COMPLETION_API,
];
// Check for the open-weight Qwen 3.8 checkpoint:
if(modelName.IndexOf("qwen3.8-2.4t-a95b") is not -1)
return
[
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2026-08-19 09:53:05 +00:00
// Check for the Qwen 3.8 Flash models. The open weights are published as
// Flash-Next, while Flash without the suffix is the production model. Both
// share the same capabilities, so one check covers them:
if(modelName.IndexOf("qwen3.8-flash") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT, Capability.VIDEO_INPUT,
Capability.TEXT_OUTPUT,
Capability.REASONING_BY_DEFAULT, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2026-08-19 09:53:05 +00:00
// Check for the multimodal Qwen 3.8 27B checkpoint:
if(modelName.IndexOf("qwen3.8-27b") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT, Capability.VIDEO_INPUT,
Capability.TEXT_OUTPUT,
Capability.REASONING_BY_DEFAULT, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
// Check for Qwen 3.5:
if(modelName.IndexOf("qwen3.5") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
// Check for Qwen 3.6 family:
if(modelName.IndexOf("qwen3.6") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.REASONING_BY_DEFAULT, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-12-30 17:30:32 +00:00
if(modelName.IndexOf("-vl-") is not -1)
return [
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-09-03 08:08:04 +00:00
return [
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
}
//
// Moonshot AI / Kimi models:
//
if (modelName.IndexOf("kimi-k3") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT, Capability.VIDEO_INPUT,
Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
if (modelName.IndexOf("kimi-k2.7-code") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
//
// Tencent Hunyuan models. Hy3 answers directly by default: its reasoning_effort
// parameter defaults to no_think, low and high must be requested. We also match
// the short name because providers offer the model as tencent/hy3, so checking
// the start of the name is not enough.
//
if (modelName.IndexOf("hunyuan") is not -1 ||
modelName.IndexOf("hy3") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
//
// Ministral models. They need their own block because their names do not contain
// "mistral" as a substring, so the block below never sees them. Only Ministral 3 accepts
// images, the 2024 models are text only, which is why the release date decides here too:
//
if (modelName.IndexOf("ministral") is not -1)
return BuildMistralCapabilities(GetMistralReleaseDate(modelName, MINISTRAL_LATEST), MINISTRAL_VISION_SINCE, MISTRAL_REASONING_NEVER);
2025-05-11 10:51:35 +00:00
//
// Mistral models:
//
if (modelName.IndexOf("mistral") is not -1 ||
modelName.IndexOf("magistral") is not -1 ||
modelName.IndexOf("voxtral") is not -1 ||
2025-05-11 10:51:35 +00:00
modelName.IndexOf("pixtral") is not -1)
{
if(modelName.IndexOf("pixtral") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
2025-09-03 08:08:04 +00:00
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
2025-05-11 10:51:35 +00:00
];
// Mistral medium 3.5:
if (modelName.IndexOf("mistral-medium-3.5") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
if (modelName.IndexOf("mistral-3") is not -1 ||
modelName.IndexOf("mistral-large-3") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
if (modelName.IndexOf("mistral-small-3") is not -1 ||
modelName.IndexOf("mistral-small-4") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
if (modelName.IndexOf("mistral-small-") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
if (modelName.IndexOf("voxtral-") is not -1)
return
[
Capability.TEXT_INPUT, Capability.SPEECH_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
// Magistral models:
if (modelName.IndexOf("magistral-") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.ALWAYS_REASONING,
Capability.CHAT_COMPLETION_API,
];
2025-12-30 17:30:32 +00:00
if (modelName.IndexOf("3.1") is not -1 ||
modelName.IndexOf("3.2") is not -1)
2025-05-11 10:51:35 +00:00
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
2025-09-03 08:08:04 +00:00
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
2025-05-11 10:51:35 +00:00
];
// Default:
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
2025-09-03 08:08:04 +00:00
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
2025-05-11 10:51:35 +00:00
];
}
//
// Grok models:
//
if (modelName.IndexOf("grok") is not -1)
{
if(modelName.IndexOf("-vision-") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
2025-09-03 08:08:04 +00:00
Capability.CHAT_COMPLETION_API,
2025-05-11 10:51:35 +00:00
];
// Grok 4 models take text, images, and video natively. Reasoning is always
// on, only the reasoning effort can be configured:
if(modelName.IndexOf("grok-4") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT, Capability.VIDEO_INPUT,
Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
if(modelName.StartsWith("grok-3-mini"))
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING,
2025-09-03 08:08:04 +00:00
Capability.CHAT_COMPLETION_API,
2025-05-11 10:51:35 +00:00
];
if(modelName.StartsWith("grok-3"))
return
2025-05-11 10:51:35 +00:00
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
2025-05-11 10:51:35 +00:00
Capability.FUNCTION_CALLING,
2025-09-03 08:08:04 +00:00
Capability.CHAT_COMPLETION_API,
];
// Any other Grok model. Without this, unknown Grok versions would fall
// through to the global default and would lose function calling:
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-09-03 08:08:04 +00:00
}
//
// OpenAI models:
//
if (modelName.IndexOf("gpt-oss") is not -1 ||
modelName.IndexOf("gpt-3.5") is not -1)
{
if(modelName.IndexOf("gpt-oss") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.WEB_SEARCH,
Capability.CHAT_COMPLETION_API,
];
if(modelName.IndexOf("gpt-3.5") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.CHAT_COMPLETION_API,
2025-05-11 10:51:35 +00:00
];
}
//
// NVIDIA Nemotron models. They are built for agentic workloads and are text
// only. Reasoning has to be requested through enable_thinking, so it is
// optional. The check also covers the quantized checkpoints such as
// NVIDIA-Nemotron-3.5-Lightning-30B-A3B-NVFP4.
//
if (modelName.IndexOf("nemotron") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
//
// Google Gemma models. Gemma is the open-weights family, while Gemini is not, which is why
// Gemma is handled here and Gemini in the Google implementation.
//
if (modelName.IndexOf("gemma") is not -1)
{
//
// Every checkpoint of the Gemma 4 generation is multimodal and understands video as
// well; there is no text-only variant. Audio input is limited to the E2B, E4B, and 12B
// checkpoints. The models can think, but only when the request asks them to: their chat
// template keeps the thinking channel closed by default.
//
if (modelName.IndexOf("gemma-4") is not -1 ||
modelName.IndexOf("gemma4") is not -1 ||
modelName.IndexOf("gemma 4") is not -1)
{
if (modelName.IndexOf("e2b") is not -1 ||
modelName.IndexOf("e4b") is not -1 ||
modelName.IndexOf("12b") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.AUDIO_INPUT, Capability.VIDEO_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.VIDEO_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
}
//
// Gemma 3 accepts images from the 4B checkpoint upwards; the 1B one is text-only. This
// generation does not reason. The check for the small checkpoint looks for "-1b" rather
// than "1b", so that a name such as gemma-3-31b does not match it.
//
if (modelName.IndexOf("gemma-3") is not -1 ||
modelName.IndexOf("gemma3") is not -1 ||
modelName.IndexOf("gemma 3") is not -1)
{
if (modelName.IndexOf("-1b") is not -1)
return
[
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
}
//
// The earlier generations take text only and were not built for tool usage:
//
return
[
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.CHAT_COMPLETION_API,
];
}
2025-12-30 17:30:32 +00:00
//
// Z AI / GLM models:
//
if (modelName.IndexOf("glm") is not -1)
{
//
// Both version checks below accept a hyphen as the version separator as well:
// Mistral serves these models as glm-5-2 and zai-glm-5-2, while everybody else
// writes the version with a dot.
//
// GLM 5.3 uses forced thinking: the reasoning effort can be lowered, but
// reasoning cannot be turned off. This check must stay in front of the
// vision check below, because quantized builds such as GLM-5.3-Flash-NVFP4
// contain a "v" and would be misread as a vision model:
if (modelName.IndexOf("glm-5.3") is not -1 ||
modelName.IndexOf("glm-5-3") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
if (modelName.IndexOf("glm-5.2") is not -1 ||
modelName.IndexOf("glm-5-2") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.REASONING_BY_DEFAULT, Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
2025-12-30 17:30:32 +00:00
if(modelName.IndexOf("v") is not -1)
return
[
Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT,
Capability.TEXT_OUTPUT,
Capability.OPTIONAL_REASONING,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
if (modelName.IndexOf("glm-4-") is not -1)
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.CHAT_COMPLETION_API,
];
return
[
Capability.TEXT_INPUT,
Capability.TEXT_OUTPUT,
Capability.FUNCTION_CALLING,
Capability.OPTIONAL_REASONING,
Capability.CHAT_COMPLETION_API,
];
}
2025-05-11 10:51:35 +00:00
// Default:
2025-09-03 08:08:04 +00:00
return [
Capability.TEXT_INPUT, Capability.TEXT_OUTPUT,
Capability.CHAT_COMPLETION_API,
];
2025-05-11 10:51:35 +00:00
}
}