From b2b0b110091ed538c06e4e7290ff5dd77e6227dc Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 11 May 2025 12:50:47 +0200 Subject: [PATCH] Added capabilities for some open source models --- .../Provider/CapabilitiesOpenSource.cs | 150 ++++++++++++++++++ .../Provider/Fireworks/ProviderFireworks.cs | 2 + .../Provider/GWDG/ProviderGWDG.cs | 2 + .../Provider/Groq/ProviderGroq.cs | 2 + .../Provider/Helmholtz/ProviderHelmholtz.cs | 2 + .../HuggingFace/ProviderHuggingFace.cs | 2 + .../Provider/Mistral/ProviderMistral.cs | 8 +- .../Provider/SelfHosted/ProviderSelfHosted.cs | 7 +- .../Provider/X/ProviderX.cs | 39 +---- 9 files changed, 167 insertions(+), 47 deletions(-) create mode 100644 app/MindWork AI Studio/Provider/CapabilitiesOpenSource.cs diff --git a/app/MindWork AI Studio/Provider/CapabilitiesOpenSource.cs b/app/MindWork AI Studio/Provider/CapabilitiesOpenSource.cs new file mode 100644 index 00000000..806b1d5b --- /dev/null +++ b/app/MindWork AI Studio/Provider/CapabilitiesOpenSource.cs @@ -0,0 +1,150 @@ +namespace AIStudio.Provider; + +public static class CapabilitiesOpenSource +{ + public static IReadOnlyCollection GetCapabilities(Model model) + { + 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, + ]; + + // The old vision models cannot do function calling: + if (modelName.IndexOf("vision") is not -1) + return [Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT, Capability.TEXT_OUTPUT]; + + // + // 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, + ]; + + // All other llama models can only do text input and output: + return [Capability.TEXT_INPUT, Capability.TEXT_OUTPUT]; + } + + // + // DeepSeek models: + // + if (modelName.IndexOf("deepseek") is not -1) + { + if(modelName.IndexOf("deepseek-r1") is not -1 || + modelName.IndexOf("deepseek r1") is not -1) + return [Capability.TEXT_INPUT, Capability.TEXT_OUTPUT, Capability.ALWAYS_REASONING]; + + return [Capability.TEXT_INPUT, Capability.TEXT_OUTPUT]; + } + + // + // Qwen models: + // + if (modelName.IndexOf("qwen") is not -1 || modelName.IndexOf("qwq") is not -1) + { + if (modelName.IndexOf("qwq") is not -1) + return [Capability.TEXT_INPUT, Capability.TEXT_OUTPUT, Capability.ALWAYS_REASONING]; + + return [Capability.TEXT_INPUT, Capability.TEXT_OUTPUT]; + } + + // + // Mistral models: + // + if (modelName.IndexOf("mistral") is not -1 || + modelName.IndexOf("pixtral") is not -1) + { + if(modelName.IndexOf("pixtral") is not -1) + return + [ + Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT, + Capability.TEXT_OUTPUT, + Capability.FUNCTION_CALLING + ]; + + if (modelName.IndexOf("3.1") is not -1) + return + [ + Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT, + Capability.TEXT_OUTPUT, + Capability.FUNCTION_CALLING + ]; + + // Default: + return + [ + Capability.TEXT_INPUT, + Capability.TEXT_OUTPUT, + Capability.FUNCTION_CALLING + ]; + } + + // + // 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, + ]; + + if(modelName.StartsWith("grok-3-mini")) + return + [ + Capability.TEXT_INPUT, + Capability.TEXT_OUTPUT, + + Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING, + ]; + + if(modelName.StartsWith("grok-3")) + return + [ + Capability.TEXT_INPUT, + Capability.TEXT_OUTPUT, + + Capability.FUNCTION_CALLING, + ]; + } + + // Default: + return [Capability.TEXT_INPUT, Capability.TEXT_OUTPUT]; + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs index 66817fc2..22164e18 100644 --- a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs +++ b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs @@ -106,6 +106,8 @@ public class ProviderFireworks(ILogger logger) : BaseProvider("https://api.firew { return Task.FromResult(Enumerable.Empty()); } + + public override IReadOnlyCollection GetModelCapabilities(Model model) => CapabilitiesOpenSource.GetCapabilities(model); #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs b/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs index c0562a69..ad41804d 100644 --- a/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs +++ b/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs @@ -107,6 +107,8 @@ public sealed class ProviderGWDG(ILogger logger) : BaseProvider("https://chat-ai var models = await this.LoadModels(token, apiKeyProvisional); return models.Where(model => model.Id.StartsWith("e5-", StringComparison.InvariantCultureIgnoreCase)); } + + public override IReadOnlyCollection GetModelCapabilities(Model model) => CapabilitiesOpenSource.GetCapabilities(model); #endregion diff --git a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs index ddf5c002..30d81ed0 100644 --- a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs +++ b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs @@ -109,6 +109,8 @@ public class ProviderGroq(ILogger logger) : BaseProvider("https://api.groq.com/o { return Task.FromResult(Enumerable.Empty()); } + + public override IReadOnlyCollection GetModelCapabilities(Model model) => CapabilitiesOpenSource.GetCapabilities(model); #endregion diff --git a/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs b/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs index b8450503..09a95387 100644 --- a/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs +++ b/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs @@ -111,6 +111,8 @@ public sealed class ProviderHelmholtz(ILogger logger) : BaseProvider("https://ap model.Id.StartsWith("text-", StringComparison.InvariantCultureIgnoreCase) || model.Id.Contains("gritlm", StringComparison.InvariantCultureIgnoreCase)); } + + public override IReadOnlyCollection GetModelCapabilities(Model model) => CapabilitiesOpenSource.GetCapabilities(model); #endregion diff --git a/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs b/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs index e98de1f9..659a8ca9 100644 --- a/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs +++ b/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs @@ -110,6 +110,8 @@ public sealed class ProviderHuggingFace : BaseProvider { return Task.FromResult(Enumerable.Empty()); } + + public override IReadOnlyCollection GetModelCapabilities(Model model) => CapabilitiesOpenSource.GetCapabilities(model); #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs index a21fe960..ed87d12f 100644 --- a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs +++ b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs @@ -165,13 +165,7 @@ public sealed class ProviderMistral(ILogger logger) : BaseProvider("https://api. ]; // Default: - return - [ - Capability.TEXT_INPUT, - Capability.TEXT_OUTPUT, - - Capability.FUNCTION_CALLING, - ]; + return CapabilitiesOpenSource.GetCapabilities(model); } #endregion diff --git a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs index 4ba45c6b..a2e997f9 100644 --- a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs +++ b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs @@ -87,8 +87,7 @@ public sealed class ProviderSelfHosted(ILogger logger, Host host, string hostnam yield break; } #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - - + public override async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { try @@ -139,7 +138,9 @@ public sealed class ProviderSelfHosted(ILogger logger, Host host, string hostnam return []; } } - + + public override IReadOnlyCollection GetModelCapabilities(Provider.Model model) => CapabilitiesOpenSource.GetCapabilities(model); + #endregion private async Task> LoadModels(string[] ignorePhrases, string[] filterPhrases, CancellationToken token, string? apiKeyProvisional = null) diff --git a/app/MindWork AI Studio/Provider/X/ProviderX.cs b/app/MindWork AI Studio/Provider/X/ProviderX.cs index 5be000eb..884c1007 100644 --- a/app/MindWork AI Studio/Provider/X/ProviderX.cs +++ b/app/MindWork AI Studio/Provider/X/ProviderX.cs @@ -111,43 +111,8 @@ public sealed class ProviderX(ILogger logger) : BaseProvider("https://api.x.ai/v return Task.FromResult>([]); } - public override IReadOnlyCollection GetModelCapabilities(Model model) - { - var modelName = model.Id.ToLowerInvariant().AsSpan(); - - if(modelName.IndexOf("-vision-") is not -1) - return - [ - Capability.TEXT_INPUT, Capability.MULTIPLE_IMAGE_INPUT, - Capability.TEXT_OUTPUT, - ]; - - if(modelName.StartsWith("grok-3-mini")) - return - [ - Capability.TEXT_INPUT, - Capability.TEXT_OUTPUT, - - Capability.ALWAYS_REASONING, Capability.FUNCTION_CALLING, - ]; - - if(modelName.StartsWith("grok-3")) - return - [ - Capability.TEXT_INPUT, - Capability.TEXT_OUTPUT, - - Capability.FUNCTION_CALLING, - ]; - - // Default capabilities: - return - [ - Capability.TEXT_INPUT, - Capability.TEXT_OUTPUT, - ]; - } - + public override IReadOnlyCollection GetModelCapabilities(Model model) => CapabilitiesOpenSource.GetCapabilities(model); + #endregion private async Task> LoadModels(string[] prefixes, CancellationToken token, string? apiKeyProvisional = null)