diff --git a/app/MindWork AI Studio/Models/Kinds/ComputerUseModelsFamily.cs b/app/MindWork AI Studio/Models/Kinds/ComputerUseModelsFamily.cs
new file mode 100644
index 00000000..f3743f10
--- /dev/null
+++ b/app/MindWork AI Studio/Models/Kinds/ComputerUseModelsFamily.cs
@@ -0,0 +1,25 @@
+using AIStudio.Provider;
+
+namespace AIStudio.Models.Kinds;
+
+///
+/// The models that work a screen instead of holding a conversation.
+///
+///
+/// They are named after the chat model they grew out of -- gemini-2.5-computer-use-preview -- and a
+/// name is all they share with it. A request without the computer use tool is refused outright:
+/// "This model requires the use of the Computer Use tool." So the resemblance is exactly the trap,
+/// and this is the rule that keeps them out of the list a person picks a chat partner from.
+///
+public sealed class ComputerUseModelsFamily : ModelFamily
+{
+ ///
+ public override ModelVendor Vendor => ModelVendor.UNKNOWN;
+
+ ///
+ public override ModelSource Source => new("https://ai.google.dev/gemini-api/docs/computer-use", new DateOnly(2026, 9, 12), "Found while testing the switch-over: the model stood in the chat list although its API refuses every request which does not carry the computer use tool.");
+
+ ///
+ protected override void Declare(ModelFamilyBuilder builder) =>
+ builder.Modifier("computer-use").AsSegment().Kind(ModelKind.COMPUTER_USE);
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Models/Kinds/ImageGenerationModelsFamily.cs b/app/MindWork AI Studio/Models/Kinds/ImageGenerationModelsFamily.cs
index dc65aa1c..edc516ce 100644
--- a/app/MindWork AI Studio/Models/Kinds/ImageGenerationModelsFamily.cs
+++ b/app/MindWork AI Studio/Models/Kinds/ImageGenerationModelsFamily.cs
@@ -35,5 +35,8 @@ public sealed class ImageGenerationModelsFamily : ModelFamily
builder.Modifier("midjourney").AsSubstring().Inherits();
builder.Modifier("image").AsSegment().Inherits();
+
+ // The other half of Grok Imagine, which the video rule steps aside for:
+ builder.Modifier("grok-imagine").AsSegment().NotContains("video").Inherits();
}
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Models/Kinds/RealtimeModelsFamily.cs b/app/MindWork AI Studio/Models/Kinds/RealtimeModelsFamily.cs
index d8378db0..6997f516 100644
--- a/app/MindWork AI Studio/Models/Kinds/RealtimeModelsFamily.cs
+++ b/app/MindWork AI Studio/Models/Kinds/RealtimeModelsFamily.cs
@@ -23,11 +23,20 @@ public sealed class RealtimeModelsFamily : ModelFamily
public override ModelVendor Vendor => ModelVendor.UNKNOWN;
///
- public override ModelSource Source => new("https://platform.openai.com/docs/guides/realtime", new DateOnly(2026, 9, 12), "Ported from the realtime marker of Provider/ModelKindExtensions.cs, where the same precedence was written as the order of two if statements.");
+ public override ModelSource Source => new("https://developers.openai.com/api/docs/models/gpt-live-1", new DateOnly(2026, 9, 12), "Ported from the realtime marker of Provider/ModelKindExtensions.cs, where the same precedence was written as the order of two if statements. GPT-Live was added after it turned up in the chat list while testing.");
///
- protected override void Declare(ModelFamilyBuilder builder) =>
+ protected override void Declare(ModelFamilyBuilder builder)
+ {
builder.Modifier("realtime").AsSubstring()
.Rank(1, THE_CONNECTION_DECIDES)
.Kind(ModelKind.REALTIME);
+
+ //
+ // The line which dropped the word. GPT-Live listens and speaks at the same time and leaves
+ // the thinking to a text model behind it, so there is even less of a conversation in it than
+ // in the realtime models it succeeds -- and nothing in the name says so any more.
+ //
+ builder.Modifier("gpt-live").AsSegment().Inherits();
+ }
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Models/Kinds/VideoGenerationModelsFamily.cs b/app/MindWork AI Studio/Models/Kinds/VideoGenerationModelsFamily.cs
index 07e6ea8b..03d31f61 100644
--- a/app/MindWork AI Studio/Models/Kinds/VideoGenerationModelsFamily.cs
+++ b/app/MindWork AI Studio/Models/Kinds/VideoGenerationModelsFamily.cs
@@ -18,7 +18,7 @@ public sealed class VideoGenerationModelsFamily : ModelFamily
public override ModelVendor Vendor => ModelVendor.UNKNOWN;
///
- public override ModelSource Source => new("https://huggingface.co/models?pipeline_tag=text-to-video", new DateOnly(2026, 9, 12), "Ported from the video generation markers of Provider/ModelKindExtensions.cs, where veo carried a trailing hyphen to say the same thing a name part says here.");
+ public override ModelSource Source => new("https://huggingface.co/models?pipeline_tag=text-to-video", new DateOnly(2026, 9, 12), "Ported from the video generation markers of Provider/ModelKindExtensions.cs, where veo carried a trailing hyphen to say the same thing a name part says here. Grok Imagine was added after it turned up in the chat list while testing; see https://docs.x.ai/docs/models.");
///
protected override void Declare(ModelFamilyBuilder builder)
@@ -32,5 +32,8 @@ public sealed class VideoGenerationModelsFamily : ModelFamily
builder.Modifier("veo").AsSegment().Inherits();
builder.Modifier("kling").AsSegment().Inherits();
+
+ // Grok Imagine makes both stills and film; the word next to it says which:
+ builder.Modifier("grok-imagine").AsSegment().AlsoContains("video").Inherits();
}
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Models/XAI/GrokFamily.cs b/app/MindWork AI Studio/Models/XAI/GrokFamily.cs
index 6a1fb4f7..3d89279c 100644
--- a/app/MindWork AI Studio/Models/XAI/GrokFamily.cs
+++ b/app/MindWork AI Studio/Models/XAI/GrokFamily.cs
@@ -34,6 +34,14 @@ public sealed class GrokFamily : ModelFamily
.Capabilities(TEXT_INPUT | MULTIPLE_IMAGE_INPUT | TEXT_OUTPUT)
.Apis(CHAT_COMPLETION_API);
+ //
+ // Grok Build is the agentic coding model behind their CLI. It reads pictures, which the
+ // family fallback does not know about, and it does not think out loud.
+ //
+ builder.Rule("grok-build").AsPrefix()
+ .Capabilities(TEXT_INPUT | MULTIPLE_IMAGE_INPUT | TEXT_OUTPUT | FUNCTION_CALLING)
+ .Apis(CHAT_COMPLETION_API);
+
builder.Rule("grok-3-mini").AsPrefix()
.Capabilities(TEXT_INPUT | TEXT_OUTPUT | FUNCTION_CALLING)
.Apis(CHAT_COMPLETION_API)
diff --git a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs
index 3b8513e8..e4a0e87e 100644
--- a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs
+++ b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs
@@ -168,9 +168,15 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, new Uri("https
{
Models =
[
+ //
+ // Asking what a model is made for, rather than only ruling out the embedding ones.
+ // Google names everything after the chat model it grew out of, so the catalog is
+ // full of names which look like something to talk to and are not: the image models,
+ // and the computer use model whose API refuses a request without its tool.
+ //
..result.Models.Where(model =>
model.Id.StartsWith("gemini-", StringComparison.OrdinalIgnoreCase) &&
- !model.IsEmbeddingModel())
+ model.IsChatModel())
.Select(this.WithDisplayNameFallback)
]
};
diff --git a/app/MindWork AI Studio/Provider/ModelKind.cs b/app/MindWork AI Studio/Provider/ModelKind.cs
index 9de9802b..75a7e49f 100644
--- a/app/MindWork AI Studio/Provider/ModelKind.cs
+++ b/app/MindWork AI Studio/Provider/ModelKind.cs
@@ -76,6 +76,16 @@ public enum ModelKind
///
REALTIME,
+ ///
+ /// The model drives a computer: it looks at a screen and says what to click next.
+ ///
+ ///
+ /// These refuse a plain conversation outright. Google's answer to a request without the computer
+ /// use tool is "This model requires the use of the Computer Use tool", so the model belongs in no
+ /// chat list, however much its name looks like the chat model it grew out of.
+ ///
+ COMPUTER_USE,
+
///
/// The model extracts text from images or scanned documents.
///
diff --git a/app/MindWork AI Studio/Provider/X/ProviderX.cs b/app/MindWork AI Studio/Provider/X/ProviderX.cs
index fb60113e..5a86efed 100644
--- a/app/MindWork AI Studio/Provider/X/ProviderX.cs
+++ b/app/MindWork AI Studio/Provider/X/ProviderX.cs
@@ -79,7 +79,12 @@ public sealed class ProviderX() : BaseProvider(LLMProviders.X, new Uri("https://
var result = await this.LoadModels(SecretStoreType.LLM_PROVIDER, ["grok-"], apiKeyProvisional, token);
return result with
{
- Models = [..result.Models.Where(n => !n.Id.Contains("-image", StringComparison.OrdinalIgnoreCase))]
+ //
+ // Asking what a model is made for rather than testing its name for a word. The word was
+ // "-image", which said nothing about grok-imagine-video: that one made films and stood
+ // in the list of things to chat with.
+ //
+ Models = [..result.Models.Where(model => model.IsChatModel())]
};
}
diff --git a/app/Tests/Models/Corpus/ExpectedChanges.cs b/app/Tests/Models/Corpus/ExpectedChanges.cs
index 36ae8bd1..2397dd8c 100644
--- a/app/Tests/Models/Corpus/ExpectedChanges.cs
+++ b/app/Tests/Models/Corpus/ExpectedChanges.cs
@@ -168,5 +168,14 @@ public static class ExpectedChanges
AnswerWanted: [TEXT_INPUT, MULTIPLE_IMAGE_INPUT, TEXT_OUTPUT, FUNCTION_CALLING, WEB_SEARCH, RESPONSES_API],
Reason: "The alias for the non-reasoning GPT-5 is claimed by the \"gpt-5-\" prefix rule and is told it always reasons, which is the one thing its name rules out.",
Source: "OpenAI names this alias as the non-reasoning model of the GPT-5 line; the corpus entry \"gpt-5\" next to it is the reasoning one."),
+
+ //
+ // A model nobody had written a rule for yet, found while testing the switch-over.
+ //
+ new(X, "grok-build-0.1",
+ AnswerToday: [TEXT_INPUT, TEXT_OUTPUT, FUNCTION_CALLING, CHAT_COMPLETION_API],
+ AnswerWanted: [TEXT_INPUT, MULTIPLE_IMAGE_INPUT, TEXT_OUTPUT, FUNCTION_CALLING, CHAT_COMPLETION_API],
+ Reason: "The agentic coding model of the Grok line reads pictures, and the family fallback it reaches says text only.",
+ Source: "https://x.ai/news/grok-build-0-1 states text and image input, tool calling, and a 256K context window."),
];
}
\ No newline at end of file
diff --git a/app/Tests/Models/Corpus/ModelCorpus.cs b/app/Tests/Models/Corpus/ModelCorpus.cs
index 327913dc..9be1e9c9 100644
--- a/app/Tests/Models/Corpus/ModelCorpus.cs
+++ b/app/Tests/Models/Corpus/ModelCorpus.cs
@@ -204,6 +204,7 @@ public static class ModelCorpus
new(X, "grok-3-mini", NAMED_BY_A_RULE),
new(X, "grok-2-vision-1212", NAMED_BY_A_RULE),
new(X, "grok-5", NAMED_BY_NO_RULE),
+ new(X, "grok-build-0.1", NAMED_BY_A_RULE),
];
///
diff --git a/app/Tests/Models/Corpus/ModelKindCorpus.cs b/app/Tests/Models/Corpus/ModelKindCorpus.cs
index efd6a196..00f3de7b 100644
--- a/app/Tests/Models/Corpus/ModelKindCorpus.cs
+++ b/app/Tests/Models/Corpus/ModelKindCorpus.cs
@@ -69,6 +69,9 @@ public static class ModelKindCorpus
new(OPEN_AI, "sora-2", VIDEO_GENERATION),
new(GOOGLE, "veo-3.0-generate-001", VIDEO_GENERATION),
new(SELF_HOSTED, "kling-video-v2", VIDEO_GENERATION),
+
+ new(X, "grok-imagine-video", VIDEO_GENERATION, AnsweredTodayAs: CHAT, Reason: "Found in the chat list while testing. No marker knew the name, and the xAI provider only kept models whose name lacks \"-image\" -- which \"-imagine\" does."),
+ new(X, "grok-imagine-video-1.5", VIDEO_GENERATION, AnsweredTodayAs: CHAT, Reason: "The same, one version on."),
];
///
@@ -108,6 +111,16 @@ public static class ModelKindCorpus
// The name the marker file names as the reason for asking this question before the others:
new(OPEN_AI, "gpt-realtime-whisper", REALTIME),
+
+ new(OPEN_AI, "gpt-live-1", REALTIME, AnsweredTodayAs: CHAT, Reason: "Found in the chat list while testing. The line which succeeds the realtime models dropped the word, and it is even less of a chat partner: it listens and speaks at once and leaves the thinking to a text model behind it."),
+ ];
+
+ ///
+ /// The models which work a screen.
+ ///
+ private static readonly ModelKindExample[] COMPUTER_USE_ENTRIES =
+ [
+ new(GOOGLE, "gemini-2.5-computer-use-preview-10-2025", COMPUTER_USE, AnsweredTodayAs: CHAT, Reason: "Found in the chat list while testing. Its API refuses every request which does not carry the computer use tool, so a conversation with it cannot even begin."),
];
///
@@ -161,6 +174,19 @@ public static class ModelKindCorpus
new(SELF_HOSTED, "llama-2-7b-chat-klingon", CHAT),
new(SELF_HOSTED, "llama3.3:70b", CHAT),
new(OPEN_AI, "gpt-5.1", CHAT),
+
+ //
+ // Three which were questioned while testing and stay all the same. Grok Build is the coding
+ // model behind the xAI CLI and answers like any other Grok. The Groq compound systems are
+ // models with tools already built in, reached through the ordinary chat completion API. And
+ // Gemini Robotics ER answers in text; it is built for pointing at things in a picture rather
+ // than for conversation, but a conversation with it works, and a model which works belongs
+ // in the list.
+ //
+ new(X, "grok-build-0.1", CHAT),
+ new(GROQ, "groq/compound", CHAT),
+ new(GROQ, "groq/compound-mini", CHAT),
+ new(GOOGLE, "gemini-robotics-er-1.5-preview", CHAT),
];
///
@@ -175,6 +201,7 @@ public static class ModelKindCorpus
..TRANSCRIPTION_ENTRIES,
..SPEECH_ENTRIES,
..REALTIME_ENTRIES,
+ ..COMPUTER_USE_ENTRIES,
..TEXT_COMPLETION_ENTRIES,
..OCR_ENTRIES,
..MODERATION_ENTRIES,