diff --git a/src/main/provider-probe.ts b/src/main/provider-probe.ts
index 917e540..b1d7389 100644
--- a/src/main/provider-probe.ts
+++ b/src/main/provider-probe.ts
@@ -535,7 +535,7 @@ async function probeProtocolConnectivity(
for (const candidate of endpoints) {
const result = await requestJson(candidate.endpoint, requestForProtocol(protocol, model, apiKey));
const message = readResponseMessage(result);
- const supported = isProtocolSupported(result.status, message);
+ const supported = isProtocolSupported(result.status, message, protocol);
const probeResult = {
baseUrl: candidate.baseUrl,
endpoint: candidate.endpoint,
@@ -982,7 +982,11 @@ function protocolHints(value: string): GatewayProviderProtocol[] {
return hints;
}
-function isProtocolSupported(status: number | undefined, message: string): boolean {
+function isProtocolSupported(
+ status: number | undefined,
+ message: string,
+ protocol?: GatewayProviderProtocol
+): boolean {
if (status === undefined) {
return false;
}
@@ -997,7 +1001,9 @@ function isProtocolSupported(status: number | undefined, message: string): boole
if (status === 400) {
const normalized = message.toLowerCase();
- return /model|max_tokens|max output|messages|input|required/.test(normalized) && !/not found|unknown endpoint|unknown route|no route/.test(normalized);
+ const schemaError = /model|max_tokens|max output|messages|input|required/.test(normalized) ||
+ (protocol === "gemini_generate_content" && /contents|generatecontentrequest|generationconfig/.test(normalized));
+ return schemaError && !/not found|unknown endpoint|unknown route|no route/.test(normalized);
}
return false;
@@ -1009,7 +1015,7 @@ export function isProviderProtocolEndpointSupportedForProbe(
protocol: GatewayProviderProtocol,
hints: GatewayProviderProtocol[] = []
): boolean {
- if (isProtocolSupported(status, message)) {
+ if (isProtocolSupported(status, message, protocol)) {
return true;
}
diff --git a/src/renderer/pages/home/App.tsx b/src/renderer/pages/home/App.tsx
index 6fcdbf2..99fdea4 100644
--- a/src/renderer/pages/home/App.tsx
+++ b/src/renderer/pages/home/App.tsx
@@ -1361,7 +1361,7 @@ function App() {
const fallbackBaseUrl = probe?.normalizedBaseUrl || providerDraft.baseUrl;
const selectableProtocols = providerSelectableProtocolsFromProbe(probe);
const selectedProtocols = providerDraft.selectedProtocols.length > 0
- ? providerDraft.selectedProtocols.filter((protocol) => selectableProtocols.length === 0 || selectableProtocols.includes(protocol))
+ ? providerDraft.selectedProtocols.filter((protocol) => !probe || selectableProtocols.includes(protocol))
: [];
if (selectableProtocols.length > 0 && selectedProtocols.length === 0) {
setProviderProbeError(t("Select at least one protocol."));
diff --git a/src/renderer/pages/home/components/providers.tsx b/src/renderer/pages/home/components/providers.tsx
index 70cf187..8c50a3c 100644
--- a/src/renderer/pages/home/components/providers.tsx
+++ b/src/renderer/pages/home/components/providers.tsx
@@ -1680,7 +1680,7 @@ export function AddProviderForm({
{probe.protocols.map((item) => {
const selectable = item.supported && selectableProtocols.includes(item.protocol);
- const checked = draft.selectedProtocols.includes(item.protocol);
+ const checked = selectable && draft.selectedProtocols.includes(item.protocol);
return (
capability.type),
- ...probe.protocols.filter((item) => item.supported).map((item) => item.protocol)
- ]);
+ return uniqueProviderProtocols(probe.protocols.filter((item) => item.supported).map((item) => item.protocol));
}
export function selectedProviderProtocolsFromCapabilities(
@@ -1772,7 +1769,7 @@ export function selectedProviderProtocolsForProbe(
): GatewayProviderProtocol[] {
const selectable = providerSelectableProtocolsFromProbe(probe);
if (selectable.length === 0) {
- return selectedProtocols.length > 0 ? uniqueProviderProtocols(selectedProtocols) : [fallback];
+ return [];
}
if (selectedProtocolsMatchPresetDefault(selectedProtocols, presetId)) {
diff --git a/tests/main/provider-probe.test.mjs b/tests/main/provider-probe.test.mjs
index 3038f7f..1291117 100644
--- a/tests/main/provider-probe.test.mjs
+++ b/tests/main/provider-probe.test.mjs
@@ -32,3 +32,16 @@ test("protocol support probe keeps auth-only fallback for unhinted endpoints", (
true
);
});
+
+test("protocol support probe treats Gemini contents validation as Gemini support only", () => {
+ const message = "HTTP 400: * GenerateContentRequest.contents: contents is not specified";
+
+ assert.equal(
+ isProviderProtocolEndpointSupportedForProbe(400, message, "gemini_generate_content", ["gemini_generate_content"]),
+ true
+ );
+ assert.equal(
+ isProviderProtocolEndpointSupportedForProbe(400, message, "openai_chat_completions", ["openai_chat_completions"]),
+ false
+ );
+});
diff --git a/tests/renderer/providers.test.ts b/tests/renderer/providers.test.ts
index 6a59f8f..5f0a1f0 100644
--- a/tests/renderer/providers.test.ts
+++ b/tests/renderer/providers.test.ts
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
import test from "node:test";
import { geminiProviderPreset } from "../../src/main/presets/gemini/index.ts";
import {
+ applyProviderProbeResult,
createProviderDraft,
providerProtocolOptions,
providerProbeCandidates,
@@ -20,3 +21,53 @@ test("Gemini preset keeps full protocol probing candidates", () => {
assert.equal(candidates.length, 1);
assert.deepEqual(candidates[0].protocols, providerProtocolOptions.map((option) => option.value));
});
+
+test("provider probe result drops unavailable selected protocols", () => {
+ const draft = {
+ ...createProviderDraft([]),
+ baseUrl: "https://generativelanguage.googleapis.com",
+ protocol: "gemini_generate_content",
+ selectedProtocols: providerProtocolOptions.map((option) => option.value)
+ };
+
+ const next = applyProviderProbeResult(draft, {
+ capabilities: [],
+ detectedProtocol: "gemini_generate_content",
+ models: [],
+ normalizedBaseUrl: draft.baseUrl,
+ protocols: providerProtocolOptions.map((option) => ({
+ endpoint: draft.baseUrl,
+ message: "HTTP 404",
+ protocol: option.value,
+ status: 404,
+ supported: false
+ }))
+ });
+
+ assert.deepEqual(next.selectedProtocols, []);
+});
+
+test("provider probe result keeps only supported selected protocols", () => {
+ const draft = {
+ ...createProviderDraft([]),
+ baseUrl: "https://generativelanguage.googleapis.com",
+ protocol: "gemini_generate_content",
+ selectedProtocols: providerProtocolOptions.map((option) => option.value)
+ };
+
+ const next = applyProviderProbeResult(draft, {
+ capabilities: [],
+ detectedProtocol: "gemini_generate_content",
+ models: [],
+ normalizedBaseUrl: draft.baseUrl,
+ protocols: providerProtocolOptions.map((option) => ({
+ endpoint: draft.baseUrl,
+ message: option.value === "gemini_generate_content" ? "HTTP 400: contents is not specified" : "HTTP 404",
+ protocol: option.value,
+ status: option.value === "gemini_generate_content" ? 400 : 404,
+ supported: option.value === "gemini_generate_content"
+ }))
+ });
+
+ assert.deepEqual(next.selectedProtocols, ["gemini_generate_content"]);
+});