mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-24 20:52:11 +00:00
First version of ProviderCapabilityOverrides
This commit is contained in:
parent
7dc927bf3b
commit
7ca4ec0814
@ -72,6 +72,7 @@ public partial class SettingsPanelProviders : SettingsPanelProviderBase
|
|||||||
{ x => x.DataHost, provider.Host },
|
{ x => x.DataHost, provider.Host },
|
||||||
{ x => x.HFInferenceProviderId, provider.HFInferenceProvider },
|
{ x => x.HFInferenceProviderId, provider.HFInferenceProvider },
|
||||||
{ x => x.AdditionalJsonApiParameters, provider.AdditionalJsonApiParameters },
|
{ x => x.AdditionalJsonApiParameters, provider.AdditionalJsonApiParameters },
|
||||||
|
{ x => x.DataCapabilityOverrides, provider.CapabilityOverrides },
|
||||||
};
|
};
|
||||||
|
|
||||||
var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>(T("Edit LLM Provider"), dialogParameters, DialogOptions.FULLSCREEN);
|
var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>(T("Edit LLM Provider"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
|
|||||||
@ -157,9 +157,29 @@
|
|||||||
</MudButton>
|
</MudButton>
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
<MudCollapse Expanded="@this.showExpertSettings" Class="@this.GetExpertStyles">
|
<MudCollapse Expanded="@this.showExpertSettings" Class="@this.GetExpertStyles">
|
||||||
<MudJustifiedText Class="mb-5">
|
<MudAlert Severity="Severity.Warning" Class="mb-4">
|
||||||
|
@T("Please be careful: wrong expert settings can break model usage, disable supported features, or make unsupported features appear available.")
|
||||||
|
</MudAlert>
|
||||||
|
<MudJustifiedText Class="mb-4">
|
||||||
@T("Please be aware: This section is for experts only. You are responsible for verifying the correctness of the additional parameters you provide to the API call. By default, AI Studio uses the OpenAI-compatible chat completions API, when that it is supported by the underlying service and model.")
|
@T("Please be aware: This section is for experts only. You are responsible for verifying the correctness of the additional parameters you provide to the API call. By default, AI Studio uses the OpenAI-compatible chat completions API, when that it is supported by the underlying service and model.")
|
||||||
</MudJustifiedText>
|
</MudJustifiedText>
|
||||||
|
<MudText Typo="Typo.subtitle2" Class="mb-2">
|
||||||
|
@T("Capability overrides")
|
||||||
|
</MudText>
|
||||||
|
<MudStack Class="mb-4">
|
||||||
|
@foreach (var capability in this.ExpertCapabilityOverrides)
|
||||||
|
{
|
||||||
|
<MudSelect T="CapabilityOverrideMode"
|
||||||
|
Value="@this.GetCapabilityOverrideMode(capability)"
|
||||||
|
ValueChanged="@(value => this.SetCapabilityOverrideMode(capability, value))"
|
||||||
|
Label="@this.GetCapabilityOverrideLabel(capability)"
|
||||||
|
Variant="Variant.Outlined">
|
||||||
|
<MudSelectItem Value="@CapabilityOverrideMode.Automatic">@T("Automatic")</MudSelectItem>
|
||||||
|
<MudSelectItem Value="@CapabilityOverrideMode.Enabled">@T("Enabled")</MudSelectItem>
|
||||||
|
<MudSelectItem Value="@CapabilityOverrideMode.Disabled">@T("Disabled")</MudSelectItem>
|
||||||
|
</MudSelect>
|
||||||
|
}
|
||||||
|
</MudStack>
|
||||||
<MudTextField T="string" Label=@T("Additional API parameters") Variant="Variant.Outlined" Lines="4" AutoGrow="true" MaxLines="10" HelperText=@T("""Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.""") Placeholder="@GetPlaceholderExpertSettings" @bind-Value="@this.AdditionalJsonApiParameters" Immediate="true" Validation="@this.ValidateAdditionalJsonApiParameters" OnBlur="@this.OnInputChangeExpertSettings"/>
|
<MudTextField T="string" Label=@T("Additional API parameters") Variant="Variant.Outlined" Lines="4" AutoGrow="true" MaxLines="10" HelperText=@T("""Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.""") Placeholder="@GetPlaceholderExpertSettings" @bind-Value="@this.AdditionalJsonApiParameters" Immediate="true" Validation="@this.ValidateAdditionalJsonApiParameters" OnBlur="@this.OnInputChangeExpertSettings"/>
|
||||||
</MudCollapse>
|
</MudCollapse>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using System.Text.Json;
|
|||||||
using AIStudio.Components;
|
using AIStudio.Components;
|
||||||
using AIStudio.Provider;
|
using AIStudio.Provider;
|
||||||
using AIStudio.Provider.HuggingFace;
|
using AIStudio.Provider.HuggingFace;
|
||||||
|
using AIStudio.Settings;
|
||||||
using AIStudio.Tools.Services;
|
using AIStudio.Tools.Services;
|
||||||
using AIStudio.Tools.Validation;
|
using AIStudio.Tools.Validation;
|
||||||
|
|
||||||
@ -83,6 +84,9 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
|||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string AdditionalJsonApiParameters { get; set; } = string.Empty;
|
public string AdditionalJsonApiParameters { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public ProviderCapabilityOverrides? DataCapabilityOverrides { get; set; }
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private RustService RustService { get; init; } = null!;
|
private RustService RustService { get; init; } = null!;
|
||||||
@ -106,6 +110,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
|||||||
private string dataLoadingModelsIssue = string.Empty;
|
private string dataLoadingModelsIssue = string.Empty;
|
||||||
private bool usesLegacySystemModelFallback;
|
private bool usesLegacySystemModelFallback;
|
||||||
private bool showExpertSettings;
|
private bool showExpertSettings;
|
||||||
|
private ProviderCapabilityOverrides capabilityOverrides = new();
|
||||||
|
|
||||||
// We get the form reference from Blazor code to validate it manually:
|
// We get the form reference from Blazor code to validate it manually:
|
||||||
private MudForm form = null!;
|
private MudForm form = null!;
|
||||||
@ -160,6 +165,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
|||||||
Host = this.DataHost,
|
Host = this.DataHost,
|
||||||
HFInferenceProvider = this.HFInferenceProviderId,
|
HFInferenceProvider = this.HFInferenceProviderId,
|
||||||
AdditionalJsonApiParameters = this.AdditionalJsonApiParameters,
|
AdditionalJsonApiParameters = this.AdditionalJsonApiParameters,
|
||||||
|
CapabilityOverrides = this.capabilityOverrides.HasOverrides ? this.capabilityOverrides : null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +184,8 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
|||||||
this.UsedInstanceNames = this.SettingsManager.ConfigurationData.Providers.Select(x => x.InstanceName.ToLowerInvariant()).ToList();
|
this.UsedInstanceNames = this.SettingsManager.ConfigurationData.Providers.Select(x => x.InstanceName.ToLowerInvariant()).ToList();
|
||||||
#pragma warning restore MWAIS0001
|
#pragma warning restore MWAIS0001
|
||||||
|
|
||||||
this.showExpertSettings = !string.IsNullOrWhiteSpace(this.AdditionalJsonApiParameters);
|
this.capabilityOverrides = this.DataCapabilityOverrides ?? new();
|
||||||
|
this.showExpertSettings = !string.IsNullOrWhiteSpace(this.AdditionalJsonApiParameters) || this.capabilityOverrides.HasOverrides;
|
||||||
|
|
||||||
// When editing, we need to load the data:
|
// When editing, we need to load the data:
|
||||||
if(this.IsEditing)
|
if(this.IsEditing)
|
||||||
@ -369,6 +376,35 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
|||||||
|
|
||||||
private void ToggleExpertSettings() => this.showExpertSettings = !this.showExpertSettings;
|
private void ToggleExpertSettings() => this.showExpertSettings = !this.showExpertSettings;
|
||||||
|
|
||||||
|
private CapabilityOverrideMode GetCapabilityOverrideMode(Capability capability) => this.capabilityOverrides.GetOverride(capability) switch
|
||||||
|
{
|
||||||
|
true => CapabilityOverrideMode.Enabled,
|
||||||
|
false => CapabilityOverrideMode.Disabled,
|
||||||
|
null => CapabilityOverrideMode.Automatic
|
||||||
|
};
|
||||||
|
|
||||||
|
private void SetCapabilityOverrideMode(Capability capability, CapabilityOverrideMode mode)
|
||||||
|
{
|
||||||
|
bool? overrideValue = mode switch
|
||||||
|
{
|
||||||
|
CapabilityOverrideMode.Enabled => true,
|
||||||
|
CapabilityOverrideMode.Disabled => false,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
this.capabilityOverrides = this.capabilityOverrides.SetOverride(capability, overrideValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCapabilityOverrideLabel(Capability capability) => capability switch
|
||||||
|
{
|
||||||
|
Capability.TEXT_INPUT => T("Text input"),
|
||||||
|
Capability.AUDIO_INPUT => T("Audio input"),
|
||||||
|
Capability.MULTIPLE_IMAGE_INPUT => T("Multiple image input"),
|
||||||
|
Capability.SPEECH_INPUT => T("Speech input"),
|
||||||
|
Capability.VIDEO_INPUT => T("Video input"),
|
||||||
|
Capability.ALWAYS_REASONING => T("Always reasoning"),
|
||||||
|
_ => capability.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
private void OnInputChangeExpertSettings()
|
private void OnInputChangeExpertSettings()
|
||||||
{
|
{
|
||||||
this.AdditionalJsonApiParameters = NormalizeAdditionalJsonApiParameters(this.AdditionalJsonApiParameters)
|
this.AdditionalJsonApiParameters = NormalizeAdditionalJsonApiParameters(this.AdditionalJsonApiParameters)
|
||||||
@ -537,10 +573,19 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
|||||||
|
|
||||||
private string GetExpertStyles => this.showExpertSettings ? "border-2 border-dashed rounded pa-2" : string.Empty;
|
private string GetExpertStyles => this.showExpertSettings ? "border-2 border-dashed rounded pa-2" : string.Empty;
|
||||||
|
|
||||||
|
private IReadOnlyList<Capability> ExpertCapabilityOverrides => ProviderCapabilityOverrides.SUPPORTED_CAPABILITIES;
|
||||||
|
|
||||||
private static string GetPlaceholderExpertSettings =>
|
private static string GetPlaceholderExpertSettings =>
|
||||||
"""
|
"""
|
||||||
"temperature": 0.5,
|
"temperature": 0.5,
|
||||||
"top_p": 0.9,
|
"top_p": 0.9,
|
||||||
"frequency_penalty": 0.0
|
"frequency_penalty": 0.0
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
private enum CapabilityOverrideMode
|
||||||
|
{
|
||||||
|
Automatic,
|
||||||
|
Enabled,
|
||||||
|
Disabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,6 +73,16 @@ CONFIG["LLM_PROVIDERS"] = {}
|
|||||||
-- -- Please do not add the enclosing curly braces {} here. Also, no trailing comma is allowed.
|
-- -- Please do not add the enclosing curly braces {} here. Also, no trailing comma is allowed.
|
||||||
-- ["AdditionalJsonApiParameters"] = "",
|
-- ["AdditionalJsonApiParameters"] = "",
|
||||||
--
|
--
|
||||||
|
-- -- Optional: expert capability overrides.
|
||||||
|
-- -- Allowed keys are exactly:
|
||||||
|
-- -- TEXT_INPUT, AUDIO_INPUT, MULTIPLE_IMAGE_INPUT, SPEECH_INPUT, VIDEO_INPUT, ALWAYS_REASONING
|
||||||
|
-- -- Allowed values are booleans only.
|
||||||
|
-- -- Missing keys keep the automatic capability detection result.
|
||||||
|
-- -- ["CapabilityOverrides"] = {
|
||||||
|
-- -- ["TEXT_INPUT"] = true,
|
||||||
|
-- -- ["VIDEO_INPUT"] = false,
|
||||||
|
-- -- },
|
||||||
|
--
|
||||||
-- -- Optional: Hugging Face inference provider. Only relevant for UsedLLMProvider = HUGGINGFACE.
|
-- -- Optional: Hugging Face inference provider. Only relevant for UsedLLMProvider = HUGGINGFACE.
|
||||||
-- -- Allowed values are: CEREBRAS, NEBIUS_AI_STUDIO, SAMBANOVA, NOVITA, HYPERBOLIC, TOGETHER_AI, FIREWORKS, HF_INFERENCE_API
|
-- -- Allowed values are: CEREBRAS, NEBIUS_AI_STUDIO, SAMBANOVA, NOVITA, HYPERBOLIC, TOGETHER_AI, FIREWORKS, HF_INFERENCE_API
|
||||||
-- -- ["HFInferenceProvider"] = "NOVITA",
|
-- -- ["HFInferenceProvider"] = "NOVITA",
|
||||||
|
|||||||
@ -33,7 +33,8 @@ public sealed record Provider(
|
|||||||
string Hostname = "http://localhost:1234",
|
string Hostname = "http://localhost:1234",
|
||||||
Host Host = Host.NONE,
|
Host Host = Host.NONE,
|
||||||
HFInferenceProvider HFInferenceProvider = HFInferenceProvider.NONE,
|
HFInferenceProvider HFInferenceProvider = HFInferenceProvider.NONE,
|
||||||
string AdditionalJsonApiParameters = "") : ConfigurationBaseObject, ISecretId
|
string AdditionalJsonApiParameters = "",
|
||||||
|
ProviderCapabilityOverrides? CapabilityOverrides = null) : ConfigurationBaseObject, ISecretId
|
||||||
{
|
{
|
||||||
private static readonly ILogger<Provider> LOGGER = Program.LOGGER_FACTORY.CreateLogger<Provider>();
|
private static readonly ILogger<Provider> LOGGER = Program.LOGGER_FACTORY.CreateLogger<Provider>();
|
||||||
|
|
||||||
@ -152,6 +153,8 @@ public sealed record Provider(
|
|||||||
additionalJsonApiParameters = string.Empty;
|
additionalJsonApiParameters = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var capabilityOverrides = ProviderCapabilityOverrides.TryParseFromLuaTable(idx, table, configPluginId, LOGGER);
|
||||||
|
|
||||||
provider = new Provider
|
provider = new Provider
|
||||||
{
|
{
|
||||||
Num = 0, // will be set later by the PluginConfigurationObject
|
Num = 0, // will be set later by the PluginConfigurationObject
|
||||||
@ -166,6 +169,7 @@ public sealed record Provider(
|
|||||||
Host = host,
|
Host = host,
|
||||||
HFInferenceProvider = hfInferenceProvider,
|
HFInferenceProvider = hfInferenceProvider,
|
||||||
AdditionalJsonApiParameters = additionalJsonApiParameters,
|
AdditionalJsonApiParameters = additionalJsonApiParameters,
|
||||||
|
CapabilityOverrides = capabilityOverrides,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle encrypted API key if present:
|
// Handle encrypted API key if present:
|
||||||
@ -241,6 +245,8 @@ public sealed record Provider(
|
|||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var capabilityOverridesLine = this.CapabilityOverrides?.ExportAsLuaTable(" ") ?? string.Empty;
|
||||||
|
|
||||||
return $$"""
|
return $$"""
|
||||||
CONFIG["LLM_PROVIDERS"][#CONFIG["LLM_PROVIDERS"]+1] = {
|
CONFIG["LLM_PROVIDERS"][#CONFIG["LLM_PROVIDERS"]+1] = {
|
||||||
["Id"] = "{{Guid.NewGuid().ToString()}}",
|
["Id"] = "{{Guid.NewGuid().ToString()}}",
|
||||||
@ -252,6 +258,7 @@ public sealed record Provider(
|
|||||||
{{hfInferenceProviderLine}}
|
{{hfInferenceProviderLine}}
|
||||||
{{apiKeyLine}}
|
{{apiKeyLine}}
|
||||||
["AdditionalJsonApiParameters"] = "{{LuaTools.EscapeLuaString(this.AdditionalJsonApiParameters)}}",
|
["AdditionalJsonApiParameters"] = "{{LuaTools.EscapeLuaString(this.AdditionalJsonApiParameters)}}",
|
||||||
|
{{capabilityOverridesLine}}
|
||||||
["Model"] = {
|
["Model"] = {
|
||||||
["Id"] = "{{LuaTools.EscapeLuaString(this.Model.Id)}}",
|
["Id"] = "{{LuaTools.EscapeLuaString(this.Model.Id)}}",
|
||||||
["DisplayName"] = "{{LuaTools.EscapeLuaString(this.Model.DisplayName ?? this.Model.Id)}}",
|
["DisplayName"] = "{{LuaTools.EscapeLuaString(this.Model.DisplayName ?? this.Model.Id)}}",
|
||||||
|
|||||||
169
app/MindWork AI Studio/Settings/ProviderCapabilityOverrides.cs
Normal file
169
app/MindWork AI Studio/Settings/ProviderCapabilityOverrides.cs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
using AIStudio.Provider;
|
||||||
|
|
||||||
|
using Lua;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
using LuaTable = Lua.LuaTable;
|
||||||
|
|
||||||
|
namespace AIStudio.Settings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional expert capability overrides for a configured LLM provider.
|
||||||
|
/// Missing values keep the automatic capability detection result.
|
||||||
|
/// </summary>
|
||||||
|
public sealed record ProviderCapabilityOverrides
|
||||||
|
{
|
||||||
|
public static readonly IReadOnlyList<Capability> SUPPORTED_CAPABILITIES =
|
||||||
|
[
|
||||||
|
Capability.TEXT_INPUT,
|
||||||
|
Capability.AUDIO_INPUT,
|
||||||
|
Capability.MULTIPLE_IMAGE_INPUT,
|
||||||
|
Capability.SPEECH_INPUT,
|
||||||
|
Capability.VIDEO_INPUT,
|
||||||
|
Capability.ALWAYS_REASONING
|
||||||
|
];
|
||||||
|
|
||||||
|
[JsonPropertyName("TEXT_INPUT")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public bool? TextInput { get; init; }
|
||||||
|
|
||||||
|
[JsonPropertyName("AUDIO_INPUT")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public bool? AudioInput { get; init; }
|
||||||
|
|
||||||
|
[JsonPropertyName("MULTIPLE_IMAGE_INPUT")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public bool? MultipleImageInput { get; init; }
|
||||||
|
|
||||||
|
[JsonPropertyName("SPEECH_INPUT")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public bool? SpeechInput { get; init; }
|
||||||
|
|
||||||
|
[JsonPropertyName("VIDEO_INPUT")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public bool? VideoInput { get; init; }
|
||||||
|
|
||||||
|
[JsonPropertyName("ALWAYS_REASONING")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public bool? AlwaysReasoning { get; init; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool HasOverrides =>
|
||||||
|
this.TextInput is not null ||
|
||||||
|
this.AudioInput is not null ||
|
||||||
|
this.MultipleImageInput is not null ||
|
||||||
|
this.SpeechInput is not null ||
|
||||||
|
this.VideoInput is not null ||
|
||||||
|
this.AlwaysReasoning is not null;
|
||||||
|
|
||||||
|
public bool? GetOverride(Capability capability) => capability switch
|
||||||
|
{
|
||||||
|
Capability.TEXT_INPUT => this.TextInput,
|
||||||
|
Capability.AUDIO_INPUT => this.AudioInput,
|
||||||
|
Capability.MULTIPLE_IMAGE_INPUT => this.MultipleImageInput,
|
||||||
|
Capability.SPEECH_INPUT => this.SpeechInput,
|
||||||
|
Capability.VIDEO_INPUT => this.VideoInput,
|
||||||
|
Capability.ALWAYS_REASONING => this.AlwaysReasoning,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
public ProviderCapabilityOverrides SetOverride(Capability capability, bool? value) => capability switch
|
||||||
|
{
|
||||||
|
Capability.TEXT_INPUT => this with { TextInput = value },
|
||||||
|
Capability.AUDIO_INPUT => this with { AudioInput = value },
|
||||||
|
Capability.MULTIPLE_IMAGE_INPUT => this with { MultipleImageInput = value },
|
||||||
|
Capability.SPEECH_INPUT => this with { SpeechInput = value },
|
||||||
|
Capability.VIDEO_INPUT => this with { VideoInput = value },
|
||||||
|
Capability.ALWAYS_REASONING => this with { AlwaysReasoning = value },
|
||||||
|
_ => this
|
||||||
|
};
|
||||||
|
|
||||||
|
public List<Capability> ApplyTo(IEnumerable<Capability> automaticCapabilities)
|
||||||
|
{
|
||||||
|
var mergedCapabilities = automaticCapabilities.Distinct().ToList();
|
||||||
|
foreach (var capability in SUPPORTED_CAPABILITIES)
|
||||||
|
{
|
||||||
|
var overrideValue = this.GetOverride(capability);
|
||||||
|
if (overrideValue == true && !mergedCapabilities.Contains(capability))
|
||||||
|
mergedCapabilities.Add(capability);
|
||||||
|
else if (overrideValue == false)
|
||||||
|
mergedCapabilities.Remove(capability);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergedCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ExportAsLuaTable(string indentation)
|
||||||
|
{
|
||||||
|
if (!this.HasOverrides)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.AppendLine($@"{indentation}[""CapabilityOverrides""] = {{");
|
||||||
|
foreach (var capability in SUPPORTED_CAPABILITIES)
|
||||||
|
{
|
||||||
|
var overrideValue = this.GetOverride(capability);
|
||||||
|
if (overrideValue is null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
builder.AppendLine($@"{indentation} [""{capability}""] = {overrideValue.Value.ToString().ToLowerInvariant()},");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append($@"{indentation}}},");
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProviderCapabilityOverrides? TryParseFromLuaTable(int idx, LuaTable providerTable, Guid configPluginId, ILogger logger)
|
||||||
|
{
|
||||||
|
if (!providerTable.TryGetValue("CapabilityOverrides", out var capabilityOverridesValue))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (capabilityOverridesValue.Type is not LuaValueType.Table || !capabilityOverridesValue.TryRead<LuaTable>(out var capabilityOverridesTable))
|
||||||
|
{
|
||||||
|
logger.LogWarning("The configured provider {ProviderIndex} contains an invalid CapabilityOverrides table. Automatic capability detection will be used instead. (Plugin ID: {PluginId})", idx, configPluginId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new ProviderCapabilityOverrides();
|
||||||
|
var previousKey = LuaValue.Nil;
|
||||||
|
while (capabilityOverridesTable.TryGetNext(previousKey, out var pair))
|
||||||
|
{
|
||||||
|
previousKey = pair.Key;
|
||||||
|
|
||||||
|
if (!pair.Key.TryRead<string>(out var keyText))
|
||||||
|
{
|
||||||
|
logger.LogWarning("The configured provider {ProviderIndex} contains a CapabilityOverrides entry with a non-string key. The entry will be ignored. (Plugin ID: {PluginId})", idx, configPluginId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryParseSupportedCapability(keyText, out var capability))
|
||||||
|
{
|
||||||
|
logger.LogWarning("The configured provider {ProviderIndex} contains an unsupported capability override '{CapabilityKey}'. The entry will be ignored. (Plugin ID: {PluginId})", idx, keyText, configPluginId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pair.Value.TryRead<bool>(out var overrideValue))
|
||||||
|
{
|
||||||
|
logger.LogWarning("The configured provider {ProviderIndex} contains a non-boolean capability override for '{CapabilityKey}'. Automatic capability detection will be used for that capability. (Plugin ID: {PluginId})", idx, keyText, configPluginId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result.SetOverride(capability, overrideValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.HasOverrides ? result : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryParseSupportedCapability(string capabilityKey, out Capability capability)
|
||||||
|
{
|
||||||
|
capability = Capability.NONE;
|
||||||
|
if (!Enum.TryParse(capabilityKey, true, out capability))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return SUPPORTED_CAPABILITIES.Contains(capability);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,11 @@ public static partial class ProviderExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="provider">The configured provider.</param>
|
/// <param name="provider">The configured provider.</param>
|
||||||
/// <returns>The capabilities of the configured model.</returns>
|
/// <returns>The capabilities of the configured model.</returns>
|
||||||
public static List<Capability> GetModelCapabilities(this Provider provider) => provider.UsedLLMProvider.GetModelCapabilities(provider.Model);
|
public static List<Capability> GetModelCapabilities(this Provider provider)
|
||||||
|
{
|
||||||
|
var automaticCapabilities = provider.UsedLLMProvider.GetModelCapabilities(provider.Model);
|
||||||
|
return provider.CapabilityOverrides?.ApplyTo(automaticCapabilities) ?? automaticCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the capabilities of a model for a specific provider.
|
/// Get the capabilities of a model for a specific provider.
|
||||||
@ -40,4 +44,4 @@ public static partial class ProviderExtensions
|
|||||||
|
|
||||||
_ => []
|
_ => []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user