diff --git a/artifacts/api-server/src/lib/aiAnalysis.ts b/artifacts/api-server/src/lib/aiAnalysis.ts index d8daa25..bdd1f64 100644 --- a/artifacts/api-server/src/lib/aiAnalysis.ts +++ b/artifacts/api-server/src/lib/aiAnalysis.ts @@ -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)}`, ); diff --git a/artifacts/skillguard/src/i18n/locales/de/admin.ts b/artifacts/skillguard/src/i18n/locales/de/admin.ts index 3b4509c..f81de1a 100644 --- a/artifacts/skillguard/src/i18n/locales/de/admin.ts +++ b/artifacts/skillguard/src/i18n/locales/de/admin.ts @@ -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", diff --git a/artifacts/skillguard/src/i18n/locales/en/admin.ts b/artifacts/skillguard/src/i18n/locales/en/admin.ts index ba2edb3..cb898e4 100644 --- a/artifacts/skillguard/src/i18n/locales/en/admin.ts +++ b/artifacts/skillguard/src/i18n/locales/en/admin.ts @@ -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", diff --git a/artifacts/skillguard/src/i18n/locales/es/admin.ts b/artifacts/skillguard/src/i18n/locales/es/admin.ts index 3dbc7c0..9f4c7cc 100644 --- a/artifacts/skillguard/src/i18n/locales/es/admin.ts +++ b/artifacts/skillguard/src/i18n/locales/es/admin.ts @@ -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", diff --git a/artifacts/skillguard/src/pages/admin.tsx b/artifacts/skillguard/src/pages/admin.tsx index a955611..2744487 100644 --- a/artifacts/skillguard/src/pages/admin.tsx +++ b/artifacts/skillguard/src/pages/admin.tsx @@ -42,14 +42,29 @@ const PROVIDER_PRESETS: Partial> = { ], }; -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 ? ( +

+ {t("admin.modelField.responsesOnlyWarning")} +

+ ) : null; + if (loading) { return (
@@ -71,6 +86,7 @@ function ModelField({ models, loading, tried, value, onChange }: {

{t("admin.modelField.found", { count: models.length })}

+ {warning}
); } @@ -83,6 +99,7 @@ function ModelField({ models, loading, tried, value, onChange }: { ? t("admin.modelField.noneFoundTried") : t("admin.modelField.noneFoundHint")}

+ {warning} ); } @@ -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 }))} /> diff --git a/attached_assets/image_1781645514678.png b/attached_assets/image_1781645514678.png new file mode 100644 index 0000000..b3641e5 Binary files /dev/null and b/attached_assets/image_1781645514678.png differ