From 918b3c87a19a118cef06aa0147f1f6a7e988c573 Mon Sep 17 00:00:00 2001 From: lazysaltyfish <7127935+lazysaltyfish@users.noreply.github.com> Date: Wed, 5 Aug 2026 10:23:39 +0700 Subject: [PATCH] fix(cli-tools): enable Apply button for dynamic OpenAI/Anthropic-compatible providers getAllAvailableModels() only consulted the static PROVIDER_MODELS catalog, which has no entry for dynamically-registered compatible providers (id like openai-compatible-chat-uuid). Fall back to the connection's own defaultModel/customModels/placeholder, mirroring ModelSelectModal.js. --- .../cli-tools/[toolId]/ToolDetailClient.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js b/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js index 2e735647..209a6d33 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js +++ b/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js @@ -81,6 +81,33 @@ export default function ToolDetailClient({ toolId, machineId }) { models.push({ value: modelValue, label: `${alias}/${m.id}`, provider: conn.provider, alias, connectionName: conn.name, modelId: m.id }); } }); + + // openai/anthropic-compatible providers are registered with a random UUID (e.g. + // "openai-compatible-chat-") that has no entry in the static PROVIDER_MODELS + // catalog, so `getModelsByProviderId` returns []. Routing still works because the + // request path uses the connection's own model config, but `hasActiveProviders` + // below would flip to false and disable the Apply button. Fall back to the + // connection's own models so these providers are usable from CLI tool pages. + if (providerModels.length === 0) { + const prefix = conn.providerSpecificData?.prefix || alias; + const fallbackModels = []; + if (conn.defaultModel) fallbackModels.push({ id: conn.defaultModel, name: conn.defaultModel }); + (conn.providerSpecificData?.customModels || []).forEach(m => { + if (m?.id && !fallbackModels.some(f => f.id === m.id)) fallbackModels.push({ id: m.id, name: m.name || m.id }); + }); + if (fallbackModels.length === 0 && conn.testStatus === "active") { + // Provider is confirmed reachable but exposes no model info anywhere; + // still let the user apply so they aren't stuck on a permanently disabled button. + fallbackModels.push({ id: "model-id", name: `${prefix}/model-id` }); + } + fallbackModels.forEach(m => { + const modelValue = `${prefix}/${m.id}`; + if (!seenModels.has(modelValue)) { + seenModels.add(modelValue); + models.push({ value: modelValue, label: `${prefix}/${m.id}`, provider: conn.provider, alias: prefix, connectionName: conn.name, modelId: m.id }); + } + }); + } }); return models; };