Resolve model profiles through the registry

This commit is contained in:
Thorsten Sommer committed 2026-09-12 10:50:12 +02:00
1 parent 9307f2c363
commit 429ca8c739
8 files changed
+551 -6

No files matched your search

@@ -0,0 +1,41 @@
using static AIStudio.Provider.Capability;
namespace AIStudio.Models.Baidu;
/// <summary>
/// ERNIE, from Baidu.
/// </summary>
/// <remarks>
/// The line calls functions and the thinking checkpoints keep the channel open whatever the request
/// says. The vision checkpoints are the exception, and the reason this family is written down at
/// all: they run in a thinking and a non-thinking mode, and tool calling is not documented for them.
/// Left to the assumption they would be offered tools nobody has said they can use.
///
/// The vision rule wins over the thinking rule by the latter stepping aside rather than by being
/// less specific: ERNIE ships a checkpoint which is both, and two rules claiming it with the same
/// right would be a coin toss.
/// </remarks>
public sealed class ErnieFamily : ModelFamily
{
/// <inheritdoc />
public override ModelVendor Vendor => ModelVendor.BAIDU;
/// <inheritdoc />
public override ModelSource Source => new("https://ernie.baidu.com/blog/", new DateOnly(2026, 9, 12), "Ported unchanged from the ERNIE block of ProviderExtensions.OpenSource.cs.");
/// <inheritdoc />
protected override void Declare(ModelFamilyBuilder builder)
{
builder.Rule("ernie").AsSubstring()
.Capabilities(TEXT_INPUT | TEXT_OUTPUT | FUNCTION_CALLING)
.Apis(CHAT_COMPLETION_API);
builder.Rule("ernie").AsSubstring().AlsoContains("thinking").NotContains("vl").Inherits()
.Reasoning(ReasoningSupport.ALWAYS);
builder.Rule("ernie").AsSubstring().AlsoContains("vl")
.Capabilities(TEXT_INPUT | MULTIPLE_IMAGE_INPUT | TEXT_OUTPUT)
.Apis(CHAT_COMPLETION_API)
.Reasoning(ReasoningSupport.OPTIONAL);
}
}
@@ -37,6 +37,31 @@ public readonly record struct ModelProfile
/// </remarks>
public static readonly ModelProfile UNKNOWN = new();
/// <summary>
/// What the app assumes about a model when no rule says anything about it.
/// </summary>
/// <remarks>
/// Hugging Face alone carries more than a hundred thousand models, so falling through here is
/// the normal case rather than a gap somebody forgot to close. The assumption describes what an
/// instruction-tuned model of the last few years does: it reads and writes text, it speaks the
/// chat completion API, and it calls functions.
///
/// Tool calling is the part that was weighed rather than observed. Counted over the corpus, 17
/// of the models which reach this answer would be described wrongly without it and 8 with it --
/// and those 8 are named, in WithoutToolCallingFamily. A model that is offered tools it cannot
/// use fails visibly, and the person turns tool calling off in the expert settings; a model
/// that is never offered any fails invisibly, because nothing ever asks it. On top of that, a
/// model released from here on is far more likely to call functions than not.
///
/// This is the whole assumption. Everything else stays unknown on purpose: a context window
/// nobody stated is not 4096 tokens, and a model whose name says nothing about images does not
/// get image input for free -- that is what the expert settings and the model plugins are for.
/// </remarks>
public static readonly ModelProfile ASSUMED = new()
{
Capabilities = Capability.TEXT_INPUT | Capability.TEXT_OUTPUT | Capability.CHAT_COMPLETION_API | Capability.FUNCTION_CALLING,
};
/// <summary>
/// What the model can do.
/// </summary>
@@ -0,0 +1,36 @@
using static AIStudio.Provider.Capability;
namespace AIStudio.Models.ServiceNow;
/// <summary>
/// Apriel, from ServiceNow.
/// </summary>
/// <remarks>
/// The Thinker models see, and they always reason: their default chat template opens the thinking
/// channel, so there is nothing to switch on and nothing to switch off.
///
/// This family exists although the line is a small one, and the reason is the tool tokens. They
/// arrived with 1.6; 1.5 has none. Left to the assumption, 1.5 would be offered tools it cannot
/// use -- which is the one direction the switch-over must not take, because nobody decided it and
/// nothing would show it until a request comes back as an error.
/// </remarks>
public sealed class AprielFamily : ModelFamily
{
/// <inheritdoc />
public override ModelVendor Vendor => ModelVendor.SERVICE_NOW;
/// <inheritdoc />
public override ModelSource Source => new("https://huggingface.co/ServiceNow-AI/Apriel-1.5-15b-Thinker", new DateOnly(2026, 9, 12), "Ported unchanged from the Apriel block of ProviderExtensions.OpenSource.cs.");
/// <inheritdoc />
protected override void Declare(ModelFamilyBuilder builder)
{
builder.Rule("apriel").AsSubstring()
.Capabilities(TEXT_INPUT | MULTIPLE_IMAGE_INPUT | TEXT_OUTPUT | FUNCTION_CALLING)
.Apis(CHAT_COMPLETION_API)
.Reasoning(ReasoningSupport.ALWAYS);
builder.Rule("apriel-1.5").AsSubstring().Inherits()
.Removes(FUNCTION_CALLING);
}
}