Improve AI model compatibility warnings and error handling

Add detection for OpenAI models that only support v1/responses and are not compatible with chat completions, providing user-friendly warnings during model selection and clearer error messages upon connection testing or AI analysis execution.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 0d01f99a-ea6a-447d-82fd-311715434a39
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: ac489071-6c6a-4584-9740-76bf6ca16040
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e32d2b99-1721-47dd-833c-98b372f48008/0d01f99a-ea6a-447d-82fd-311715434a39/upEITG1
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
Replit Agent 2026-06-16 21:35:24 +00:00
parent 1451ce790f
commit 29853219bc
6 changed files with 32 additions and 1 deletions

View file

@ -137,6 +137,12 @@ async function callOpenAiCompatible(
});
if (!res.ok) {
const body = await res.text();
if (body.includes("v1/responses")) {
throw new Error(
`Das Modell "${provider.model}" unterstützt nur /v1/responses, nicht /v1/chat/completions. ` +
`Bitte wählen Sie ein Chat-kompatibles Modell (z.\u202fB. gpt-4o, gpt-4-turbo, gpt-3.5-turbo).`,
);
}
throw new Error(
`HTTP ${res.status}: ${redactSecrets(body.slice(0, 300), provider.apiToken)}`,
);

View file

@ -16,6 +16,8 @@ export default {
noneFoundTried: "Keine Modelle gefunden bitte das Modell manuell eingeben.",
noneFoundHint:
"Testen Sie die Verbindung, um verfügbare Modelle automatisch zu laden, oder geben Sie das Modell manuell ein.",
responsesOnlyWarning:
"Dieses Modell unterstützt nur /v1/responses, nicht /v1/chat/completions. Die KI-Analyse wird fehlschlagen. Bitte wählen Sie ein Chat-kompatibles Modell (z.\u202fB. gpt-4o, gpt-4-turbo).",
},
providers: {
heading: "KI-Provider",

View file

@ -16,6 +16,8 @@ export default {
noneFoundTried: "No models found please enter the model manually.",
noneFoundHint:
"Test the connection to load available models automatically, or enter the model manually.",
responsesOnlyWarning:
"This model only supports /v1/responses, not /v1/chat/completions. AI analysis will fail. Please choose a chat-compatible model (e.g. gpt-4o, gpt-4-turbo).",
},
providers: {
heading: "AI providers",

View file

@ -16,6 +16,8 @@ export default {
noneFoundTried: "No se encontraron modelos: introduzca el modelo manualmente.",
noneFoundHint:
"Pruebe la conexión para cargar automáticamente los modelos disponibles, o introduzca el modelo manualmente.",
responsesOnlyWarning:
"Este modelo solo admite /v1/responses, no /v1/chat/completions. El análisis de IA fallará. Seleccione un modelo compatible con chat (p.\u202fej. gpt-4o, gpt-4-turbo).",
},
providers: {
heading: "Proveedores de IA",

View file

@ -42,14 +42,29 @@ const PROVIDER_PRESETS: Partial<Record<AiProviderApiType, ProviderPreset[]>> = {
],
};
function ModelField({ models, loading, tried, value, onChange }: {
const RESPONSES_ONLY_RE = /^o\d/i;
function isResponsesOnlyModel(model: string, apiType: string): boolean {
return apiType === "openai" && RESPONSES_ONLY_RE.test(model.trim());
}
function ModelField({ models, loading, tried, value, onChange, apiType }: {
models: string[];
loading: boolean;
tried: boolean;
value: string;
onChange: (v: string) => void;
apiType: string;
}) {
const { t } = useTranslation();
const warnResponsesOnly = value && isResponsesOnlyModel(value, apiType);
const warning = warnResponsesOnly ? (
<p className="text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded-md px-2 py-1.5">
{t("admin.modelField.responsesOnlyWarning")}
</p>
) : null;
if (loading) {
return (
<div className="grid gap-2">
@ -71,6 +86,7 @@ function ModelField({ models, loading, tried, value, onChange }: {
</SelectContent>
</Select>
<p className="text-xs text-muted-foreground">{t("admin.modelField.found", { count: models.length })}</p>
{warning}
</div>
);
}
@ -83,6 +99,7 @@ function ModelField({ models, loading, tried, value, onChange }: {
? t("admin.modelField.noneFoundTried")
: t("admin.modelField.noneFoundHint")}
</p>
{warning}
</div>
);
}
@ -368,6 +385,7 @@ function ProviderTab() {
models={addModels}
loading={addModelsLoading}
tried={addModelsTried}
apiType={addForm.apiType}
value={addForm.model}
onChange={(v) => setAddForm(f => ({ ...f, model: v }))}
/>
@ -498,6 +516,7 @@ function ProviderTab() {
models={editModels}
loading={editModelsLoading}
tried={editModelsTried}
apiType={editForm.apiType}
value={editForm.model}
onChange={(v) => setEditForm(f => ({ ...f, model: v }))}
/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB