diff --git a/app/MindWork AI Studio/Models/Google/AqaFamily.cs b/app/MindWork AI Studio/Models/Google/AqaFamily.cs new file mode 100644 index 00000000..f9f6c0d5 --- /dev/null +++ b/app/MindWork AI Studio/Models/Google/AqaFamily.cs @@ -0,0 +1,32 @@ +using AIStudio.Provider; + +using static AIStudio.Provider.Capability; + +namespace AIStudio.Models.Google; + +/// +/// AQA, which answers a question out of the passages it was handed. +/// +/// +/// Attributed Question Answering, and the one entry in Google's catalog whose whole name is three +/// letters. It answers on generateAnswer rather than on generateContent, together with the semantic +/// retriever, and what comes back is the answer, the passages it rests on, and an estimate of +/// whether the question could be answered from them at all. +/// +/// Bound to Google, and it has to be: three letters are three letters, and a rule that short has no +/// business meeting a name from somewhere else. The catalog holds exactly one model it can match. +/// +public sealed class AqaFamily : ModelFamily +{ + /// + public override ModelVendor Vendor => ModelVendor.GOOGLE; + + /// + public override ModelSource Source => new("https://ai.google.dev/gemini-api/docs/semantic_retrieval", new DateOnly(2026, 9, 19), "Reads 7,168 tokens and writes 1,024, which is a size for an answer rather than for a conversation. The route it answers on is generateAnswer, so nothing the app sends over the chat completion API reaches it."); + + /// + protected override void Declare(ModelFamilyBuilder builder) => + builder.Rule("aqa").AsExact().OnlyOn(LLMProviders.GOOGLE) + .Capabilities(TEXT_INPUT | TEXT_OUTPUT) + .Kind(ModelKind.GROUNDED_ANSWERING); +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Models/Google/GoogleAgentFamily.cs b/app/MindWork AI Studio/Models/Google/GoogleAgentFamily.cs new file mode 100644 index 00000000..bc305a45 --- /dev/null +++ b/app/MindWork AI Studio/Models/Google/GoogleAgentFamily.cs @@ -0,0 +1,42 @@ +using AIStudio.Provider; + +using static AIStudio.Provider.Capability; + +namespace AIStudio.Models.Google; + +/// +/// The Google models which are handed a job rather than a message. +/// +/// +/// Both of these answer on the Interactions API alone, never on generateContent: one request starts +/// an autonomous loop which plans, runs code, manages files and searches the web, and a research +/// run takes minutes rather than seconds. A chat request does not time out against them -- it never +/// arrives. +/// +/// Deep Research is the reason these rules are bound to Google instead of standing among the kinds. +/// Perplexity sells something under that name too, and sonar-deep-research is an ordinary chat +/// model with web search bolted on, stated in its own family. The same two words, two different +/// things, and only the provider tells them apart. Antigravity needs no such guard -- nobody else +/// names a model that -- but it is a statement about Google's catalog all the same, so it stands +/// where the other one stands. +/// +public sealed class GoogleAgentFamily : ModelFamily +{ + /// + public override ModelVendor Vendor => ModelVendor.GOOGLE; + + /// + public override ModelSource Source => new("https://ai.google.dev/gemini-api/docs/deep-research", new DateOnly(2026, 9, 19), "Deep Research runs only through the Interactions API and only in the background, because a single run takes five to twenty minutes. The Antigravity agent is documented at https://ai.google.dev/gemini-api/docs/antigravity-agent and works the same way, on a sandbox Google hosts."); + + /// + protected override void Declare(ModelFamilyBuilder builder) + { + builder.Rule("deep-research").AsPrefix().OnlyOn(LLMProviders.GOOGLE) + .Capabilities(TEXT_INPUT) + .Kind(ModelKind.AGENT); + + builder.Rule("antigravity").AsSegment().OnlyOn(LLMProviders.GOOGLE) + .Capabilities(TEXT_INPUT) + .Kind(ModelKind.AGENT); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Models/Google/LyriaFamily.cs b/app/MindWork AI Studio/Models/Google/LyriaFamily.cs new file mode 100644 index 00000000..f53697d4 --- /dev/null +++ b/app/MindWork AI Studio/Models/Google/LyriaFamily.cs @@ -0,0 +1,35 @@ +using AIStudio.Provider; + +using static AIStudio.Provider.Capability; + +namespace AIStudio.Models.Google; + +/// +/// Lyria, which writes music from a description. +/// +/// +/// Nothing knew the name, so the catalog answered for it the way it answers for everything nobody +/// wrote a rule for: a chat model which reads text, writes text and calls tools. What comes back is +/// a stereo recording with instruments and, from 3.5 on, sung lyrics. +/// +/// Nobody ran into it because the Google provider showed only names beginning with "gemini", which +/// kept four Lyria models out of sight along with the two Gemma models somebody actually wants. The +/// prefix is gone now, so the rule has to carry what the prefix carried by accident. +/// +/// Whole name parts rather than a substring, for the reason Imagen gives next door. The rule is not +/// bound to Google, unlike the agent ones: wherever a model called Lyria turns up, it is this. +/// +public sealed class LyriaFamily : ModelFamily +{ + /// + public override ModelVendor Vendor => ModelVendor.GOOGLE; + + /// + public override ModelSource Source => new("https://ai.google.dev/gemini-api/docs/music-generation", new DateOnly(2026, 9, 19), "A description goes in and 44.1 kHz stereo music comes out, with vocals and timed lyrics from Lyria 3.5 on. The realtime variant holds a connection open instead, which the realtime rule states and outranks this with."); + + /// + protected override void Declare(ModelFamilyBuilder builder) => + builder.Rule("lyria").AsSegment() + .Capabilities(TEXT_INPUT) + .Kind(ModelKind.MUSIC_GENERATION); +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Plugins/models/plugin.lua b/app/MindWork AI Studio/Plugins/models/plugin.lua index 82f691ae..d68f2b3a 100644 --- a/app/MindWork AI Studio/Plugins/models/plugin.lua +++ b/app/MindWork AI Studio/Plugins/models/plugin.lua @@ -146,10 +146,13 @@ MODELS = {} -- -- -- What the model is made for. Optional, defaults to CHAT. -- -- Allowed values are: CHAT, TEXT_COMPLETION, EMBEDDING, RERANKING, --- -- IMAGE_GENERATION, VIDEO_GENERATION, TRANSCRIPTION, SPEECH_SYNTHESIS, --- -- REALTIME, COMPUTER_USE, OCR, MODERATION, OTHER +-- -- IMAGE_GENERATION, VIDEO_GENERATION, MUSIC_GENERATION, TRANSCRIPTION, +-- -- SPEECH_SYNTHESIS, REALTIME, COMPUTER_USE, AGENT, GROUNDED_ANSWERING, +-- -- OCR, MODERATION, OTHER -- -- This decides which lists the model appears in. Use OTHER for entries --- -- which are no models at all. +-- -- which are no models at all. Use AGENT for a model which is handed a +-- -- job and works on it by itself, and GROUNDED_ANSWERING for one which +-- -- answers out of passages it is given and cites them. -- ["KIND"] = "CHAT", -- -- -- Optional: how many tokens the model reads and writes in one diff --git a/app/MindWork AI Studio/Provider/ModelKind.cs b/app/MindWork AI Studio/Provider/ModelKind.cs index 75a7e49f..f6baa0b3 100644 --- a/app/MindWork AI Studio/Provider/ModelKind.cs +++ b/app/MindWork AI Studio/Provider/ModelKind.cs @@ -52,6 +52,16 @@ public enum ModelKind /// VIDEO_GENERATION, + /// + /// The model composes music. + /// + /// + /// Audio comes out of it, but not speech: instruments, arrangement, and in Lyria's case singing + /// with lyrics. Neither the speech synthesis list nor any other one fits, and a chat request to + /// such a model gets nothing back that reads like an answer. + /// + MUSIC_GENERATION, + /// /// The model transcribes audio into text. /// @@ -86,6 +96,27 @@ public enum ModelKind /// COMPUTER_USE, + /// + /// The model runs an errand of its own instead of answering. + /// + /// + /// One request starts a loop which plans, calls tools, runs code and reads the web, and it can + /// take minutes. Google serves its research and coding agents this way, through an API of their + /// own which a chat request never reaches. Note that the name alone decides nothing here: what + /// Perplexity calls deep research is an ordinary chat model with web search. + /// + AGENT, + + /// + /// The model answers a question out of sources handed to it, and says where the answer came from. + /// + /// + /// Built for retrieval rather than for conversation: it is given passages along with the + /// question, and returns the answer, the citations, and an estimate of whether the question + /// could be answered from them at all. Reached through a route of its own. + /// + GROUNDED_ANSWERING, + /// /// The model extracts text from images or scanned documents. /// diff --git a/app/Tests/Models/Corpus/ModelKindCorpus.cs b/app/Tests/Models/Corpus/ModelKindCorpus.cs index 7c78ba6d..ac73ea69 100644 --- a/app/Tests/Models/Corpus/ModelKindCorpus.cs +++ b/app/Tests/Models/Corpus/ModelKindCorpus.cs @@ -193,6 +193,46 @@ public static class ModelKindCorpus new(GOOGLE, "lyria-realtime-exp", REALTIME), ]; + /// + /// The models which write music. + /// + /// + /// All four off Google's own catalog. They were never seen because the provider showed only + /// names beginning with "gemini" -- the same prefix which kept Gemma out, which is why it had + /// to go and why these needed a rule of their own before it could. + /// + private static readonly ModelKindExample[] MUSIC_ENTRIES = + [ + new(GOOGLE, "lyria-3.5", MUSIC_GENERATION), + new(GOOGLE, "lyria-3-pro-preview", MUSIC_GENERATION), + new(GOOGLE, "lyria-3-clip-preview", MUSIC_GENERATION), + ]; + + /// + /// The models which are handed a job instead of a message. + /// + /// + /// The last two are the point of binding these rules to Google. Perplexity sells deep research + /// as well, and what it sells is a chat model -- so the same two words have to mean different + /// things at different providers, which is exactly what a binding is for. + /// + private static readonly ModelKindExample[] AGENT_ENTRIES = + [ + new(GOOGLE, "deep-research-preview-04-2026", AGENT), + new(GOOGLE, "deep-research-max-preview-04-2026", AGENT), + new(GOOGLE, "deep-research-pro-preview-12-2025", AGENT), + new(GOOGLE, "antigravity-preview-05-2026", AGENT), + new(GOOGLE, "antigravity-preview-09-2026", AGENT), + ]; + + /// + /// The model which answers out of what it was handed, and says where the answer came from. + /// + private static readonly ModelKindExample[] GROUNDED_ANSWERING_ENTRIES = + [ + new(GOOGLE, "aqa", GROUNDED_ANSWERING), + ]; + /// /// The models which work a screen. /// @@ -303,6 +343,15 @@ public static class ModelKindCorpus new(PERPLEXITY, "sonar-reasoning-pro", CHAT), new(PERPLEXITY, "sonar-deep-research", CHAT), + // + // The other two deep research models of the world, and the reason Google's rule is bound + // to Google and written as a prefix. Perplexity and OpenAI both sell something under that + // name which answers over the API the app already speaks, so both stay chat models. Only + // Google's own line, whose names start with the words, is handed a job instead. + // + new(OPEN_AI, "o3-deep-research", CHAT), + new(OPEN_AI, "o4-mini-deep-research", CHAT), + // // The counter-sample to the three rules above, taken off the same three catalogs. Every // one of these carries a word which now means something -- code, live, image -- without @@ -342,6 +391,9 @@ public static class ModelKindCorpus ..TRANSCRIPTION_ENTRIES, ..SPEECH_ENTRIES, ..REALTIME_ENTRIES, + ..MUSIC_ENTRIES, + ..AGENT_ENTRIES, + ..GROUNDED_ANSWERING_ENTRIES, ..COMPUTER_USE_ENTRIES, ..TEXT_COMPLETION_ENTRIES, ..OCR_ENTRIES,