mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-09-27 01:53:36 +00:00
Port the Anthropic and Google families
This commit is contained in:
parent
730bd1c7c4
commit
c6cbce6e01
60
app/MindWork AI Studio/Models/Anthropic/ClaudeFamily.cs
Normal file
60
app/MindWork AI Studio/Models/Anthropic/ClaudeFamily.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using static AIStudio.Provider.Capability;
|
||||
|
||||
namespace AIStudio.Models.Anthropic;
|
||||
|
||||
/// <summary>
|
||||
/// Claude, all of it: the 3.x models, the 4.x models, and the 5 line.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// One family, because every Claude is the same shape and always has been -- text and images in,
|
||||
/// text out, tool calling, one API. What each generation adds to that is a single sentence about
|
||||
/// thinking, and the rules below are almost nothing but those sentences.
|
||||
///
|
||||
/// The first rule is the family's own fallback, and it is a statement rather than an accident: a
|
||||
/// Claude nobody has written a rule for yet is still a Claude, and every one of them so far reads
|
||||
/// images and calls tools. It answers for whole name parts, so every rule bound to the start of a
|
||||
/// name beats it, whatever their lengths -- which is what lets it sit first and mean "unless".
|
||||
/// </remarks>
|
||||
public sealed class ClaudeFamily : ModelFamily
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override ModelVendor Vendor => ModelVendor.ANTHROPIC;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ModelSource Source => new("https://docs.anthropic.com/en/docs/about-claude/models", new DateOnly(2026, 9, 11), "Ported unchanged from the rules in ProviderExtensions.Anthropic.cs: one shape for all of Claude, and one sentence per generation about how it thinks.");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Declare(ModelFamilyBuilder builder)
|
||||
{
|
||||
builder.Rule("claude").AsSegment()
|
||||
.Capabilities(TEXT_INPUT | MULTIPLE_IMAGE_INPUT | TEXT_OUTPUT | FUNCTION_CALLING)
|
||||
.Apis(CHAT_COMPLETION_API);
|
||||
|
||||
//
|
||||
// The 3.x models say nothing beyond the shape above, so nothing is written for them: the
|
||||
// previous rules had a branch for "claude-3-" which returned exactly what its fallback
|
||||
// returned. Only 3.7 differs, by being the first Claude which could be asked to think.
|
||||
//
|
||||
builder.Rule("claude-3-7").AsPrefix().InheritsFrom("claude")
|
||||
.Reasoning(ReasoningSupport.OPTIONAL);
|
||||
|
||||
// The 4.x models think when a thinking budget is given, and not otherwise:
|
||||
builder.Rule("claude-opus-4").AsPrefix().InheritsFrom("claude")
|
||||
.Reasoning(ReasoningSupport.OPTIONAL);
|
||||
|
||||
builder.Rule("claude-sonnet-4").AsPrefix().InheritsFrom("claude-opus-4");
|
||||
builder.Rule("claude-haiku-4-5").AsPrefix().InheritsFrom("claude-opus-4");
|
||||
|
||||
// Opus 5 and Sonnet 5 think adaptively unless thinking is turned off:
|
||||
builder.Rule("claude-opus-5").AsPrefix().InheritsFrom("claude")
|
||||
.Reasoning(ReasoningSupport.ON_BY_DEFAULT);
|
||||
|
||||
builder.Rule("claude-sonnet-5").AsPrefix().InheritsFrom("claude-opus-5");
|
||||
|
||||
// Fable 5 and Mythos 5 always think, and there is no switch for it:
|
||||
builder.Rule("claude-fable-5").AsPrefix().InheritsFrom("claude")
|
||||
.Reasoning(ReasoningSupport.ALWAYS);
|
||||
|
||||
builder.Rule("claude-mythos-5").AsPrefix().InheritsFrom("claude-fable-5");
|
||||
}
|
||||
}
|
||||
69
app/MindWork AI Studio/Models/Google/GeminiFamily.cs
Normal file
69
app/MindWork AI Studio/Models/Google/GeminiFamily.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using static AIStudio.Provider.Capability;
|
||||
|
||||
namespace AIStudio.Models.Google;
|
||||
|
||||
/// <summary>
|
||||
/// The Gemini chat models.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A Gemini reads everything -- text, images, audio, speech, video -- writes text, and calls tools.
|
||||
/// That is the first rule, and it is the family's own fallback for a Gemini nobody has written a
|
||||
/// rule for yet. What the generations add to it is how they think, and the older exceptions take
|
||||
/// something away instead.
|
||||
///
|
||||
/// Every generation gets a line of its own, including the dotted ones. The dot is a version
|
||||
/// boundary rather than a name part boundary, deliberately -- it is what keeps llama3 and llama3.1
|
||||
/// apart -- so a rule for "gemini-3" does not answer for "gemini-3.1", and each has to say so
|
||||
/// itself. The previous rules searched for "gemini-3" anywhere in the name and covered unreleased
|
||||
/// versions by accident; the price of not doing that is a line per generation, and the verification
|
||||
/// run names any model of the corpus which finds no rule.
|
||||
/// </remarks>
|
||||
public sealed class GeminiFamily : ModelFamily
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override ModelVendor Vendor => ModelVendor.GOOGLE;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ModelSource Source => new("https://ai.google.dev/gemini-api/docs/models", new DateOnly(2026, 9, 11), "Ported unchanged from the rules in ProviderExtensions.Google.cs: one shape for all of Gemini, one sentence per generation about thinking.");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Declare(ModelFamilyBuilder builder)
|
||||
{
|
||||
builder.Rule("gemini").AsSegment()
|
||||
.Capabilities(TEXT_INPUT | MULTIPLE_IMAGE_INPUT | AUDIO_INPUT | SPEECH_INPUT | VIDEO_INPUT | TEXT_OUTPUT | FUNCTION_CALLING)
|
||||
.Apis(CHAT_COMPLETION_API);
|
||||
|
||||
// The one Gemini which only ever read text and images:
|
||||
builder.Rule("gemini-1.0-pro-vision").AsPrefix()
|
||||
.Capabilities(TEXT_INPUT | MULTIPLE_IMAGE_INPUT | TEXT_OUTPUT)
|
||||
.Apis(CHAT_COMPLETION_API);
|
||||
|
||||
//
|
||||
// The live model, which belongs to a different API: it speaks back, and it is the one
|
||||
// Gemini that does not look at still images.
|
||||
//
|
||||
builder.Rule("gemini-2.0-flash-live").AsPrefix()
|
||||
.Capabilities(TEXT_INPUT | AUDIO_INPUT | SPEECH_INPUT | VIDEO_INPUT | TEXT_OUTPUT | SPEECH_OUTPUT | FUNCTION_CALLING)
|
||||
.Apis(CHAT_COMPLETION_API);
|
||||
|
||||
builder.Rule("gemini-2.5").AsPrefix().InheritsFrom("gemini")
|
||||
.Reasoning(ReasoningSupport.ALWAYS);
|
||||
|
||||
//
|
||||
// The one exception of the 2.5 line: it can think, but only when asked. From the 3.x line
|
||||
// on, even the Flash Lite models think at their lowest level.
|
||||
//
|
||||
builder.Rule("gemini-2.5-flash-lite").AsPrefix().InheritsFrom("gemini")
|
||||
.Reasoning(ReasoningSupport.OPTIONAL);
|
||||
|
||||
builder.Rule("gemini-3").AsPrefix().InheritsFrom("gemini")
|
||||
.Reasoning(ReasoningSupport.ALWAYS);
|
||||
|
||||
builder.Rule("gemini-3.1").AsPrefix().InheritsFrom("gemini-3");
|
||||
builder.Rule("gemini-3.7").AsPrefix().InheritsFrom("gemini-3");
|
||||
|
||||
// The two rolling aliases, which carry no version number and point at the current line:
|
||||
builder.Rule("gemini-flash-latest").AsExact().InheritsFrom("gemini-3");
|
||||
builder.Rule("gemini-pro-latest").AsExact().InheritsFrom("gemini-3");
|
||||
}
|
||||
}
|
||||
42
app/MindWork AI Studio/Models/Google/GeminiImageFamily.cs
Normal file
42
app/MindWork AI Studio/Models/Google/GeminiImageFamily.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using static AIStudio.Provider.Capability;
|
||||
|
||||
namespace AIStudio.Models.Google;
|
||||
|
||||
/// <summary>
|
||||
/// The Gemini models which draw as well as write.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// They are named like every other Gemini, with a version and a size, and the only thing setting
|
||||
/// them apart is the name part "image". So the rules here are the generation rules of the chat
|
||||
/// family with that one part required on top, and requiring it is exactly what makes them win: two
|
||||
/// rules reaching equally far into a name are separated by how many conditions they carry.
|
||||
///
|
||||
/// What they can do is nearly the opposite of what their generation can. They write images, which
|
||||
/// no chat Gemini does, and they call no tools, which every chat Gemini does. Reading them as chat
|
||||
/// models of their line -- which is what happens when nobody asks about the image part first --
|
||||
/// promises tool calling that is not there.
|
||||
/// </remarks>
|
||||
public sealed class GeminiImageFamily : ModelFamily
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override ModelVendor Vendor => ModelVendor.GOOGLE;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ModelSource Source => new("https://ai.google.dev/gemini-api/docs/image-generation", new DateOnly(2026, 9, 11), "Ported unchanged from the rules in ProviderExtensions.Google.cs: images out, no tool calling, and thinking from the 3 line on.");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Declare(ModelFamilyBuilder builder)
|
||||
{
|
||||
builder.Rule("gemini-2.5").AsPrefix().AlsoContains("image")
|
||||
.Capabilities(TEXT_INPUT | MULTIPLE_IMAGE_INPUT | TEXT_OUTPUT | IMAGE_OUTPUT)
|
||||
.Apis(CHAT_COMPLETION_API);
|
||||
|
||||
// From the 3 line on they think about a complicated prompt, and it cannot be switched off:
|
||||
builder.Rule("gemini-3").AsPrefix().AlsoContains("image").Inherits()
|
||||
.Reasoning(ReasoningSupport.ALWAYS);
|
||||
|
||||
// Only the 3.1 Flash image models watch video:
|
||||
builder.Rule("gemini-3.1").AsPrefix().AlsoContains("image").Inherits()
|
||||
.Capabilities(VIDEO_INPUT);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
using AIStudio.Provider;
|
||||
|
||||
using static AIStudio.Provider.Capability;
|
||||
|
||||
namespace AIStudio.Models.Google;
|
||||
|
||||
/// <summary>
|
||||
/// Google's embedding models, which turn text into a vector and answer nothing.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The previous rules answered for these with the Google default: images in, text out, tool
|
||||
/// calling. None of it is true, and the app already knows better -- it asks every provider for its
|
||||
/// embedding models through a method of its own.
|
||||
///
|
||||
/// The Gemini one needs a rule of its own for another reason: its name begins with "gemini", so
|
||||
/// without one it would be read as a chat model of the family.
|
||||
/// </remarks>
|
||||
public sealed class GoogleEmbeddingFamily : ModelFamily
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override ModelVendor Vendor => ModelVendor.GOOGLE;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ModelSource Source => new("https://ai.google.dev/gemini-api/docs/embeddings", new DateOnly(2026, 9, 11), "The app lists these under IProvider.GetEmbeddingModels, which is where the statement that they embed comes from.");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Declare(ModelFamilyBuilder builder)
|
||||
{
|
||||
builder.Rule("text-embedding-004").AsExact()
|
||||
.Capabilities(TEXT_INPUT | EMBEDDING)
|
||||
.Kind(ModelKind.EMBEDDING);
|
||||
|
||||
builder.Rule("gemini-embedding").AsPrefix().Inherits();
|
||||
}
|
||||
}
|
||||
32
app/MindWork AI Studio/Models/Google/ImagenFamily.cs
Normal file
32
app/MindWork AI Studio/Models/Google/ImagenFamily.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using AIStudio.Provider;
|
||||
|
||||
using static AIStudio.Provider.Capability;
|
||||
|
||||
namespace AIStudio.Models.Google;
|
||||
|
||||
/// <summary>
|
||||
/// Imagen, which draws a picture from a description and does nothing else.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The previous rules had no branch for it. Its name does not contain "gemini", so it fell to the
|
||||
/// last line of the Google function and was answered as a chat model: reads images, writes text,
|
||||
/// calls functions. Not one of the three is true, and the one thing it does -- writing an image --
|
||||
/// was not said at all.
|
||||
///
|
||||
/// Whole name parts, not a substring: "imagen" also sits inside "imagenet" and "reimagined", and a
|
||||
/// chat model carrying such a word would be turned into an image generator by a careless match.
|
||||
/// </remarks>
|
||||
public sealed class ImagenFamily : ModelFamily
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override ModelVendor Vendor => ModelVendor.GOOGLE;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ModelSource Source => new("https://ai.google.dev/gemini-api/docs/imagen", new DateOnly(2026, 9, 11), "A description goes in and an image comes out; there is no conversation and no tool calling.");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Declare(ModelFamilyBuilder builder) =>
|
||||
builder.Rule("imagen").AsSegment()
|
||||
.Capabilities(TEXT_INPUT | IMAGE_OUTPUT)
|
||||
.Kind(ModelKind.IMAGE_GENERATION);
|
||||
}
|
||||
@ -66,7 +66,6 @@ GOOGLE | gemini-3-pro-image | ALWAYS_REASONING, CHAT_COMPLETION_API, IMAGE_OUTPU
|
||||
GOOGLE | gemini-3.1-flash-image | ALWAYS_REASONING, CHAT_COMPLETION_API, IMAGE_OUTPUT, MULTIPLE_IMAGE_INPUT, TEXT_INPUT, TEXT_OUTPUT, VIDEO_INPUT
|
||||
GOOGLE | gemini-flash-latest | ALWAYS_REASONING, AUDIO_INPUT, CHAT_COMPLETION_API, FUNCTION_CALLING, MULTIPLE_IMAGE_INPUT, SPEECH_INPUT, TEXT_INPUT, TEXT_OUTPUT, VIDEO_INPUT
|
||||
GOOGLE | gemini-pro-latest | ALWAYS_REASONING, AUDIO_INPUT, CHAT_COMPLETION_API, FUNCTION_CALLING, MULTIPLE_IMAGE_INPUT, SPEECH_INPUT, TEXT_INPUT, TEXT_OUTPUT, VIDEO_INPUT
|
||||
GOOGLE | imagen-4.0-generate-001 | CHAT_COMPLETION_API, FUNCTION_CALLING, MULTIPLE_IMAGE_INPUT, TEXT_INPUT, TEXT_OUTPUT
|
||||
GROQ | llama-3.3-70b-versatile | CHAT_COMPLETION_API, FUNCTION_CALLING, TEXT_INPUT, TEXT_OUTPUT
|
||||
GROQ | moonshotai/kimi-k2-instruct | CHAT_COMPLETION_API, FUNCTION_CALLING, TEXT_INPUT, TEXT_OUTPUT
|
||||
GROQ | openai/gpt-oss-120b | CHAT_COMPLETION_API, FUNCTION_CALLING, TEXT_INPUT, TEXT_OUTPUT, WEB_SEARCH
|
||||
|
||||
@ -103,6 +103,16 @@ public static class ExpectedChanges
|
||||
Reason: "A transcription model reaches the global fallback and is told it calls functions.",
|
||||
Source: "Same model family as the Whisper entries the app lists for Fireworks and GWDG."),
|
||||
|
||||
//
|
||||
// An image generation model. It draws a picture from a description; there is no
|
||||
// conversation in it and nothing to call a function with.
|
||||
//
|
||||
new(GOOGLE, "imagen-4.0-generate-001",
|
||||
AnswerToday: [TEXT_INPUT, MULTIPLE_IMAGE_INPUT, TEXT_OUTPUT, FUNCTION_CALLING, CHAT_COMPLETION_API],
|
||||
AnswerWanted: [TEXT_INPUT, IMAGE_OUTPUT],
|
||||
Reason: "An image generation model is answered with the Google default for everything which is not a Gemini: it is told it reads images, writes text, and calls functions, and the one thing it does is not said at all.",
|
||||
Source: "Provider/Google/ProviderGoogle.cs keeps only names beginning with \"gemini-\" in its chat model list, so this model is never a chat model to begin with; Provider/ModelKindExtensions.cs classifies image generation separately."),
|
||||
|
||||
//
|
||||
// One model, two spellings, two answers.
|
||||
//
|
||||
|
||||
@ -30,6 +30,8 @@ public sealed class PortingDifferenceTests
|
||||
private static readonly IReadOnlyList<LLMProviders> PROVIDERS_ALREADY_PORTED =
|
||||
[
|
||||
LLMProviders.OPEN_AI,
|
||||
LLMProviders.ANTHROPIC,
|
||||
LLMProviders.GOOGLE,
|
||||
];
|
||||
|
||||
[Test]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user