refactor(api): extrai validators enterprise-cloud + probe compartilhado de validation.ts (#4923)

Integrado em release/v3.8.36 (validation.ts split fatia 3 — enterprise-cloud + probe)
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-24 09:52:23 -03:00
committed by GitHub
parent 1cb246215a
commit 6035fd8ba1
4 changed files with 767 additions and 700 deletions

View File

@@ -25,41 +25,12 @@ import {
} from "@/shared/network/safeOutboundFetch";
import { getProviderOutboundGuard } from "@/shared/network/outboundUrlGuard";
import { resolveNvidiaValidationModel } from "@/lib/providers/nvidiaValidationModel";
import { getGigachatAccessToken } from "@omniroute/open-sse/services/gigachatAuth.ts";
import { validateQoderCliPat } from "@omniroute/open-sse/services/qoderCli.ts";
import {
AZURE_AI_DEFAULT_BASE_URL,
buildAzureAiChatUrl,
buildAzureAiModelsUrl,
} from "@omniroute/open-sse/config/azureAi.ts";
import {
discoverBedrockNativeModels,
isBedrockNativeApiError,
isBedrockNativeAuthError,
} from "@omniroute/open-sse/services/bedrock.ts";
import {
DATAROBOT_DEFAULT_BASE_URL,
buildDataRobotCatalogUrl,
buildDataRobotChatUrl,
isDataRobotDeploymentUrl,
} from "@omniroute/open-sse/config/datarobot.ts";
import {
OCI_DEFAULT_BASE_URL,
buildOciChatUrl,
buildOciModelsUrl,
} from "@omniroute/open-sse/config/oci.ts";
import {
SAP_DEFAULT_BASE_URL,
buildSapChatUrl,
buildSapModelsUrl,
getSapResourceGroup,
isSapDeploymentUrl,
} from "@omniroute/open-sse/config/sap.ts";
import {
WATSONX_DEFAULT_BASE_URL,
buildWatsonxChatUrl,
buildWatsonxModelsUrl,
} from "@omniroute/open-sse/config/watsonx.ts";
import {
buildRunwayApiUrl,
buildRunwayHeaders,
@@ -76,16 +47,11 @@ import {
OPENAI_LIKE_FORMATS,
GEMINI_LIKE_FORMATS,
normalizeBaseUrl,
normalizeAzureOpenAIBaseUrl,
normalizeAnthropicBaseUrl,
normalizeClaudeCodeCompatibleBaseUrl,
addModelsSuffix,
resolveBaseUrl,
resolveChatUrl,
normalizeHerokuChatUrl,
normalizeDatabricksChatUrl,
normalizeSnowflakeChatUrl,
normalizeGigachatChatUrl,
} from "./validation/urlHelpers";
import {
STANDARD_USER_AGENT,
@@ -121,6 +87,19 @@ import {
validateJulesProvider,
validateInnerAiProvider,
} from "./validation/webProvidersB";
import { validateDirectChatProvider } from "./validation/directChatProbe";
import {
validateHerokuProvider,
validateDatabricksProvider,
validateDataRobotProvider,
validateSnowflakeProvider,
validateGigachatProvider,
validateAzureOpenAIProvider,
validateAzureAiProvider,
validateWatsonxProvider,
validateOciProvider,
validateSapProvider,
} from "./validation/cloudProviders";
// isRetryableProxyTarget + isSecurityBlockError now live in ./validation/transport. Re-export them
// here to preserve the historical public surface (tests + route handlers import them via this module).
@@ -274,47 +253,6 @@ async function validateOpenAILikeProvider({
}
}
async function validateDirectChatProvider({
url,
headers,
body,
providerSpecificData = {},
isLocal = false,
}: any) {
try {
const response = await validationWrite(
url,
{
method: "POST",
headers: applyCustomUserAgent(headers, providerSpecificData),
body: JSON.stringify(body),
},
isLocal
);
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (
response.ok ||
response.status === 400 ||
response.status === 422 ||
response.status === 429
) {
return { valid: true, error: null };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
return { valid: false, error: `Validation failed: ${response.status}` };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
export async function validateCommandCodeProvider({ apiKey, providerSpecificData = {} }: any) {
const entry = getRegistryEntry("command-code");
const baseUrl = normalizeBaseUrl(entry?.baseUrl || "https://api.commandcode.ai");
@@ -1012,631 +950,6 @@ async function validateBailianCodingPlanProvider({ apiKey, providerSpecificData
}
}
async function validateHerokuProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl = normalizeBaseUrl(providerSpecificData.baseUrl);
if (!baseUrl) {
return { valid: false, error: "Missing base URL" };
}
return validateDirectChatProvider({
url: normalizeHerokuChatUrl(baseUrl),
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: {
model: providerSpecificData.validationModelId || "claude-4-sonnet",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
async function validateDatabricksProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl = normalizeBaseUrl(providerSpecificData.baseUrl);
if (!baseUrl) {
return { valid: false, error: "Missing base URL" };
}
return validateDirectChatProvider({
url: normalizeDatabricksChatUrl(baseUrl),
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: {
model: providerSpecificData.validationModelId || "databricks-meta-llama-3-3-70b-instruct",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
async function validateDataRobotProvider({ apiKey, providerSpecificData = {} }: any) {
const configuredBaseUrl =
normalizeBaseUrl(providerSpecificData.baseUrl) || DATAROBOT_DEFAULT_BASE_URL;
if (isDataRobotDeploymentUrl(configuredBaseUrl)) {
return validateDirectChatProvider({
url: buildDataRobotChatUrl(configuredBaseUrl),
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: {
model: providerSpecificData.validationModelId || "datarobot-deployed-llm",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
const catalogUrl = buildDataRobotCatalogUrl(configuredBaseUrl);
if (!catalogUrl) {
return { valid: false, error: "Invalid DataRobot base URL" };
}
try {
const response = await validationRead(catalogUrl, {
method: "GET",
headers: buildBearerHeaders(apiKey, providerSpecificData),
});
if (response.ok) {
return { valid: true, error: null, method: "gateway_catalog" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "gateway_catalog",
warning: "Rate limited, but credentials are valid",
};
}
if (response.status >= 400 && response.status < 500) {
return { valid: true, error: null, method: "gateway_catalog" };
}
return { valid: false, error: `Validation failed: ${response.status}` };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
async function validateSnowflakeProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl = normalizeBaseUrl(providerSpecificData.baseUrl);
if (!baseUrl) {
return { valid: false, error: "Missing base URL" };
}
const usesProgrammaticAccessToken = typeof apiKey === "string" && apiKey.startsWith("pat/");
return validateDirectChatProvider({
url: normalizeSnowflakeChatUrl(baseUrl),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${usesProgrammaticAccessToken ? apiKey.slice(4) : apiKey}`,
"X-Snowflake-Authorization-Token-Type": usesProgrammaticAccessToken
? "PROGRAMMATIC_ACCESS_TOKEN"
: "KEYPAIR_JWT",
},
body: {
model: providerSpecificData.validationModelId || "llama3.3-70b",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
async function validateGigachatProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl =
normalizeBaseUrl(providerSpecificData.baseUrl) || "https://gigachat.devices.sberbank.ru/api/v1";
let token;
try {
token = await getGigachatAccessToken({ credentials: apiKey });
} catch (error: any) {
if (String(error?.message || "").match(/\b(401|403)\b/)) {
return { valid: false, error: "Invalid API key" };
}
return toValidationErrorResult(error);
}
return validateDirectChatProvider({
url: normalizeGigachatChatUrl(baseUrl),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token.accessToken}`,
Accept: "application/json",
},
body: {
model: providerSpecificData.validationModelId || "GigaChat-2-Pro",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
async function validateAzureOpenAIProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl);
if (!rawBaseUrl) {
return { valid: false, error: "Missing base URL" };
}
const baseUrl = normalizeAzureOpenAIBaseUrl(rawBaseUrl);
const apiVersion =
typeof providerSpecificData.validationApiVersion === "string" &&
providerSpecificData.validationApiVersion.trim()
? providerSpecificData.validationApiVersion.trim()
: "2024-12-01-preview";
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
"api-key": apiKey,
},
providerSpecificData
);
const encodedVersion = encodeURIComponent(apiVersion);
for (const probeUrl of [
`${baseUrl}/openai/deployments?api-version=${encodedVersion}`,
`${baseUrl}/openai/models?api-version=${encodedVersion}`,
]) {
try {
const response = await validationRead(probeUrl, { method: "GET", headers });
if (response.ok) {
return { valid: true, error: null, method: "azure_probe" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 400 || response.status === 404 || response.status === 405) {
continue;
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "azure_probe",
warning: "Rate limited, but credentials are valid",
};
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error) {
return toValidationErrorResult(error);
}
}
const deploymentId =
typeof providerSpecificData.validationModelId === "string"
? providerSpecificData.validationModelId.trim()
: "";
if (!deploymentId) {
return {
valid: true,
error: null,
warning:
"Azure key accepted, but no deployment name was provided for a chat probe. Set Model ID to validate a specific deployment.",
};
}
const chatUrl = `${baseUrl}/openai/deployments/${encodeURIComponent(deploymentId)}/chat/completions?api-version=${encodedVersion}`;
const response = await validationWrite(chatUrl, {
method: "POST",
headers,
body: JSON.stringify({
model: deploymentId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
});
if (
response.ok ||
response.status === 400 ||
response.status === 422 ||
response.status === 429
) {
return { valid: true, error: null, method: "chat_probe" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 404) {
return {
valid: true,
error: null,
method: "chat_probe",
warning: "Azure credentials are valid, but the requested deployment was not found.",
};
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
return { valid: false, error: `Validation failed: ${response.status}` };
}
async function validateAzureAiProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || AZURE_AI_DEFAULT_BASE_URL;
const modelsUrl = buildAzureAiModelsUrl(rawBaseUrl);
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
"api-key": apiKey,
},
providerSpecificData
);
try {
const response = await validationRead(modelsUrl, {
method: "GET",
headers,
});
if (response.ok) {
return { valid: true, error: null, method: "azure_ai_models" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "azure_ai_models",
warning: "Rate limited, but credentials are valid",
};
}
} catch {
// Fall through to chat probe when /models is unavailable.
}
const validationModelId =
typeof providerSpecificData.validationModelId === "string"
? providerSpecificData.validationModelId.trim()
: "";
if (!validationModelId) {
return {
valid: false,
error: "Endpoint /models unavailable. Provide a Model ID to validate via /chat/completions.",
};
}
const chatUrl = buildAzureAiChatUrl(
rawBaseUrl,
providerSpecificData.apiType === "responses" ? "responses" : "chat"
);
const chatBody =
providerSpecificData.apiType === "responses"
? {
model: validationModelId,
input: "test",
max_output_tokens: 1,
}
: {
model: validationModelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
};
try {
const response = await validationWrite(chatUrl, {
method: "POST",
headers,
body: JSON.stringify(chatBody),
});
if (
response.ok ||
response.status === 400 ||
response.status === 404 ||
response.status === 422 ||
response.status === 429
) {
return { valid: true, error: null, method: "azure_ai_chat_probe" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error: any) {
return toValidationErrorResult(error);
}
return { valid: false, error: "Connection failed while testing Azure AI Foundry" };
}
async function validateWatsonxProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || WATSONX_DEFAULT_BASE_URL;
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
providerSpecificData
);
try {
const response = await validationRead(buildWatsonxModelsUrl(rawBaseUrl), {
method: "GET",
headers,
});
if (response.ok) {
return { valid: true, error: null, method: "watsonx_models" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "watsonx_models",
warning: "Rate limited, but credentials are valid",
};
}
} catch {
// Fall through to chat probe when /models is unavailable.
}
const validationModelId =
typeof providerSpecificData.validationModelId === "string" &&
providerSpecificData.validationModelId.trim()
? providerSpecificData.validationModelId.trim()
: "ibm/granite-3-3-8b-instruct";
try {
const response = await validationWrite(buildWatsonxChatUrl(rawBaseUrl), {
method: "POST",
headers,
body: JSON.stringify({
model: validationModelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
});
if (
response.ok ||
response.status === 400 ||
response.status === 404 ||
response.status === 422 ||
response.status === 429
) {
return {
valid: true,
error: null,
method: "watsonx_chat_probe",
...(response.status === 404
? { warning: "watsonx credentials are valid, but the requested model is not enabled." }
: {}),
};
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error: any) {
return toValidationErrorResult(error);
}
return { valid: false, error: "Connection failed while testing watsonx.ai" };
}
async function validateOciProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || OCI_DEFAULT_BASE_URL;
const projectId =
typeof providerSpecificData.projectId === "string" && providerSpecificData.projectId.trim()
? providerSpecificData.projectId.trim()
: typeof providerSpecificData.project === "string" && providerSpecificData.project.trim()
? providerSpecificData.project.trim()
: "";
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
...(projectId ? { "OpenAI-Project": projectId } : {}),
},
providerSpecificData
);
try {
const response = await validationRead(buildOciModelsUrl(rawBaseUrl), {
method: "GET",
headers,
});
if (response.ok) {
return { valid: true, error: null, method: "oci_models" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "oci_models",
warning: "Rate limited, but credentials are valid",
};
}
} catch {
// Fall through to chat/responses probe when /models is unavailable.
}
const validationModelId =
typeof providerSpecificData.validationModelId === "string" &&
providerSpecificData.validationModelId.trim()
? providerSpecificData.validationModelId.trim()
: "openai.gpt-oss-20b";
const apiType = providerSpecificData.apiType === "responses" ? "responses" : "chat";
const body =
apiType === "responses"
? {
model: validationModelId,
input: "test",
max_output_tokens: 1,
}
: {
model: validationModelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
};
try {
const response = await validationWrite(buildOciChatUrl(rawBaseUrl, apiType), {
method: "POST",
headers,
body: JSON.stringify(body),
});
if (
response.ok ||
response.status === 400 ||
response.status === 404 ||
response.status === 422 ||
response.status === 429
) {
return {
valid: true,
error: null,
method: apiType === "responses" ? "oci_responses_probe" : "oci_chat_probe",
...(response.status === 404
? { warning: "OCI credentials are valid, but the requested model was not found." }
: {}),
};
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error: any) {
return toValidationErrorResult(error);
}
return { valid: false, error: "Connection failed while testing OCI Generative AI" };
}
async function validateSapProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || SAP_DEFAULT_BASE_URL;
const resourceGroup = getSapResourceGroup(providerSpecificData);
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
"AI-Resource-Group": resourceGroup,
},
providerSpecificData
);
try {
const response = await validationRead(buildSapModelsUrl(rawBaseUrl), {
method: "GET",
headers,
});
if (response.ok) {
return { valid: true, error: null, method: "sap_models" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "sap_models",
warning: "Rate limited, but credentials are valid",
};
}
} catch {
// Fall through to deployment probe when the discovery API is unavailable.
}
const canProbeChat =
isSapDeploymentUrl(rawBaseUrl) || /\/chat\/completions$/i.test(normalizeBaseUrl(rawBaseUrl));
if (!canProbeChat) {
return {
valid: false,
error:
"SAP validation needs either a reachable AI_API_URL or a deployment URL in providerSpecificData.baseUrl",
};
}
const validationModelId =
typeof providerSpecificData.validationModelId === "string" &&
providerSpecificData.validationModelId.trim()
? providerSpecificData.validationModelId.trim()
: "gpt-4o";
try {
const response = await validationWrite(buildSapChatUrl(rawBaseUrl), {
method: "POST",
headers,
body: JSON.stringify({
model: validationModelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
});
if (
response.ok ||
response.status === 400 ||
response.status === 404 ||
response.status === 422 ||
response.status === 429
) {
return {
valid: true,
error: null,
method: "sap_chat_probe",
...(response.status === 404
? { warning: "SAP credentials are valid, but the deployment URL or model was not found." }
: {}),
};
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error: any) {
return toValidationErrorResult(error);
}
return { valid: false, error: "Connection failed while testing SAP Generative AI Hub" };
}
async function validateRekaProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || "https://api.reka.ai/v1";
const headers = buildRekaHeaders(apiKey, providerSpecificData);

View File

@@ -0,0 +1,669 @@
// Enterprise-cloud provider key validators: heroku, databricks, datarobot, snowflake, gigachat,
// azure-openai, azure-ai, watsonx, oci, sap. Extracted from validation.ts (god-file decomposition) —
// top-level functions with no dispatcher-state captures; behavior is byte-identical to the inline defs.
import {
normalizeBaseUrl,
normalizeAzureOpenAIBaseUrl,
normalizeHerokuChatUrl,
normalizeDatabricksChatUrl,
normalizeSnowflakeChatUrl,
normalizeGigachatChatUrl,
} from "./urlHelpers";
import { applyCustomUserAgent, buildBearerHeaders } from "./headers";
import { toValidationErrorResult, validationRead, validationWrite } from "./transport";
import { validateDirectChatProvider } from "./directChatProbe";
import { getGigachatAccessToken } from "@omniroute/open-sse/services/gigachatAuth.ts";
import {
AZURE_AI_DEFAULT_BASE_URL,
buildAzureAiChatUrl,
buildAzureAiModelsUrl,
} from "@omniroute/open-sse/config/azureAi.ts";
import {
DATAROBOT_DEFAULT_BASE_URL,
buildDataRobotCatalogUrl,
buildDataRobotChatUrl,
isDataRobotDeploymentUrl,
} from "@omniroute/open-sse/config/datarobot.ts";
import {
OCI_DEFAULT_BASE_URL,
buildOciChatUrl,
buildOciModelsUrl,
} from "@omniroute/open-sse/config/oci.ts";
import {
SAP_DEFAULT_BASE_URL,
buildSapChatUrl,
buildSapModelsUrl,
getSapResourceGroup,
isSapDeploymentUrl,
} from "@omniroute/open-sse/config/sap.ts";
import {
WATSONX_DEFAULT_BASE_URL,
buildWatsonxChatUrl,
buildWatsonxModelsUrl,
} from "@omniroute/open-sse/config/watsonx.ts";
export async function validateHerokuProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl = normalizeBaseUrl(providerSpecificData.baseUrl);
if (!baseUrl) {
return { valid: false, error: "Missing base URL" };
}
return validateDirectChatProvider({
url: normalizeHerokuChatUrl(baseUrl),
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: {
model: providerSpecificData.validationModelId || "claude-4-sonnet",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
export async function validateDatabricksProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl = normalizeBaseUrl(providerSpecificData.baseUrl);
if (!baseUrl) {
return { valid: false, error: "Missing base URL" };
}
return validateDirectChatProvider({
url: normalizeDatabricksChatUrl(baseUrl),
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: {
model: providerSpecificData.validationModelId || "databricks-meta-llama-3-3-70b-instruct",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
export async function validateDataRobotProvider({ apiKey, providerSpecificData = {} }: any) {
const configuredBaseUrl =
normalizeBaseUrl(providerSpecificData.baseUrl) || DATAROBOT_DEFAULT_BASE_URL;
if (isDataRobotDeploymentUrl(configuredBaseUrl)) {
return validateDirectChatProvider({
url: buildDataRobotChatUrl(configuredBaseUrl),
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: {
model: providerSpecificData.validationModelId || "datarobot-deployed-llm",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
const catalogUrl = buildDataRobotCatalogUrl(configuredBaseUrl);
if (!catalogUrl) {
return { valid: false, error: "Invalid DataRobot base URL" };
}
try {
const response = await validationRead(catalogUrl, {
method: "GET",
headers: buildBearerHeaders(apiKey, providerSpecificData),
});
if (response.ok) {
return { valid: true, error: null, method: "gateway_catalog" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "gateway_catalog",
warning: "Rate limited, but credentials are valid",
};
}
if (response.status >= 400 && response.status < 500) {
return { valid: true, error: null, method: "gateway_catalog" };
}
return { valid: false, error: `Validation failed: ${response.status}` };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
export async function validateSnowflakeProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl = normalizeBaseUrl(providerSpecificData.baseUrl);
if (!baseUrl) {
return { valid: false, error: "Missing base URL" };
}
const usesProgrammaticAccessToken = typeof apiKey === "string" && apiKey.startsWith("pat/");
return validateDirectChatProvider({
url: normalizeSnowflakeChatUrl(baseUrl),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${usesProgrammaticAccessToken ? apiKey.slice(4) : apiKey}`,
"X-Snowflake-Authorization-Token-Type": usesProgrammaticAccessToken
? "PROGRAMMATIC_ACCESS_TOKEN"
: "KEYPAIR_JWT",
},
body: {
model: providerSpecificData.validationModelId || "llama3.3-70b",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
export async function validateGigachatProvider({ apiKey, providerSpecificData = {} }: any) {
const baseUrl =
normalizeBaseUrl(providerSpecificData.baseUrl) || "https://gigachat.devices.sberbank.ru/api/v1";
let token;
try {
token = await getGigachatAccessToken({ credentials: apiKey });
} catch (error: any) {
if (String(error?.message || "").match(/\b(401|403)\b/)) {
return { valid: false, error: "Invalid API key" };
}
return toValidationErrorResult(error);
}
return validateDirectChatProvider({
url: normalizeGigachatChatUrl(baseUrl),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token.accessToken}`,
Accept: "application/json",
},
body: {
model: providerSpecificData.validationModelId || "GigaChat-2-Pro",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
},
providerSpecificData,
});
}
export async function validateAzureOpenAIProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl);
if (!rawBaseUrl) {
return { valid: false, error: "Missing base URL" };
}
const baseUrl = normalizeAzureOpenAIBaseUrl(rawBaseUrl);
const apiVersion =
typeof providerSpecificData.validationApiVersion === "string" &&
providerSpecificData.validationApiVersion.trim()
? providerSpecificData.validationApiVersion.trim()
: "2024-12-01-preview";
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
"api-key": apiKey,
},
providerSpecificData
);
const encodedVersion = encodeURIComponent(apiVersion);
for (const probeUrl of [
`${baseUrl}/openai/deployments?api-version=${encodedVersion}`,
`${baseUrl}/openai/models?api-version=${encodedVersion}`,
]) {
try {
const response = await validationRead(probeUrl, { method: "GET", headers });
if (response.ok) {
return { valid: true, error: null, method: "azure_probe" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 400 || response.status === 404 || response.status === 405) {
continue;
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "azure_probe",
warning: "Rate limited, but credentials are valid",
};
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error) {
return toValidationErrorResult(error);
}
}
const deploymentId =
typeof providerSpecificData.validationModelId === "string"
? providerSpecificData.validationModelId.trim()
: "";
if (!deploymentId) {
return {
valid: true,
error: null,
warning:
"Azure key accepted, but no deployment name was provided for a chat probe. Set Model ID to validate a specific deployment.",
};
}
const chatUrl = `${baseUrl}/openai/deployments/${encodeURIComponent(deploymentId)}/chat/completions?api-version=${encodedVersion}`;
const response = await validationWrite(chatUrl, {
method: "POST",
headers,
body: JSON.stringify({
model: deploymentId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
});
if (
response.ok ||
response.status === 400 ||
response.status === 422 ||
response.status === 429
) {
return { valid: true, error: null, method: "chat_probe" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 404) {
return {
valid: true,
error: null,
method: "chat_probe",
warning: "Azure credentials are valid, but the requested deployment was not found.",
};
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
return { valid: false, error: `Validation failed: ${response.status}` };
}
export async function validateAzureAiProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || AZURE_AI_DEFAULT_BASE_URL;
const modelsUrl = buildAzureAiModelsUrl(rawBaseUrl);
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
"api-key": apiKey,
},
providerSpecificData
);
try {
const response = await validationRead(modelsUrl, {
method: "GET",
headers,
});
if (response.ok) {
return { valid: true, error: null, method: "azure_ai_models" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "azure_ai_models",
warning: "Rate limited, but credentials are valid",
};
}
} catch {
// Fall through to chat probe when /models is unavailable.
}
const validationModelId =
typeof providerSpecificData.validationModelId === "string"
? providerSpecificData.validationModelId.trim()
: "";
if (!validationModelId) {
return {
valid: false,
error: "Endpoint /models unavailable. Provide a Model ID to validate via /chat/completions.",
};
}
const chatUrl = buildAzureAiChatUrl(
rawBaseUrl,
providerSpecificData.apiType === "responses" ? "responses" : "chat"
);
const chatBody =
providerSpecificData.apiType === "responses"
? {
model: validationModelId,
input: "test",
max_output_tokens: 1,
}
: {
model: validationModelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
};
try {
const response = await validationWrite(chatUrl, {
method: "POST",
headers,
body: JSON.stringify(chatBody),
});
if (
response.ok ||
response.status === 400 ||
response.status === 404 ||
response.status === 422 ||
response.status === 429
) {
return { valid: true, error: null, method: "azure_ai_chat_probe" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error: any) {
return toValidationErrorResult(error);
}
return { valid: false, error: "Connection failed while testing Azure AI Foundry" };
}
export async function validateWatsonxProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || WATSONX_DEFAULT_BASE_URL;
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
providerSpecificData
);
try {
const response = await validationRead(buildWatsonxModelsUrl(rawBaseUrl), {
method: "GET",
headers,
});
if (response.ok) {
return { valid: true, error: null, method: "watsonx_models" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "watsonx_models",
warning: "Rate limited, but credentials are valid",
};
}
} catch {
// Fall through to chat probe when /models is unavailable.
}
const validationModelId =
typeof providerSpecificData.validationModelId === "string" &&
providerSpecificData.validationModelId.trim()
? providerSpecificData.validationModelId.trim()
: "ibm/granite-3-3-8b-instruct";
try {
const response = await validationWrite(buildWatsonxChatUrl(rawBaseUrl), {
method: "POST",
headers,
body: JSON.stringify({
model: validationModelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
});
if (
response.ok ||
response.status === 400 ||
response.status === 404 ||
response.status === 422 ||
response.status === 429
) {
return {
valid: true,
error: null,
method: "watsonx_chat_probe",
...(response.status === 404
? { warning: "watsonx credentials are valid, but the requested model is not enabled." }
: {}),
};
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error: any) {
return toValidationErrorResult(error);
}
return { valid: false, error: "Connection failed while testing watsonx.ai" };
}
export async function validateOciProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || OCI_DEFAULT_BASE_URL;
const projectId =
typeof providerSpecificData.projectId === "string" && providerSpecificData.projectId.trim()
? providerSpecificData.projectId.trim()
: typeof providerSpecificData.project === "string" && providerSpecificData.project.trim()
? providerSpecificData.project.trim()
: "";
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
...(projectId ? { "OpenAI-Project": projectId } : {}),
},
providerSpecificData
);
try {
const response = await validationRead(buildOciModelsUrl(rawBaseUrl), {
method: "GET",
headers,
});
if (response.ok) {
return { valid: true, error: null, method: "oci_models" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "oci_models",
warning: "Rate limited, but credentials are valid",
};
}
} catch {
// Fall through to chat/responses probe when /models is unavailable.
}
const validationModelId =
typeof providerSpecificData.validationModelId === "string" &&
providerSpecificData.validationModelId.trim()
? providerSpecificData.validationModelId.trim()
: "openai.gpt-oss-20b";
const apiType = providerSpecificData.apiType === "responses" ? "responses" : "chat";
const body =
apiType === "responses"
? {
model: validationModelId,
input: "test",
max_output_tokens: 1,
}
: {
model: validationModelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
};
try {
const response = await validationWrite(buildOciChatUrl(rawBaseUrl, apiType), {
method: "POST",
headers,
body: JSON.stringify(body),
});
if (
response.ok ||
response.status === 400 ||
response.status === 404 ||
response.status === 422 ||
response.status === 429
) {
return {
valid: true,
error: null,
method: apiType === "responses" ? "oci_responses_probe" : "oci_chat_probe",
...(response.status === 404
? { warning: "OCI credentials are valid, but the requested model was not found." }
: {}),
};
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error: any) {
return toValidationErrorResult(error);
}
return { valid: false, error: "Connection failed while testing OCI Generative AI" };
}
export async function validateSapProvider({ apiKey, providerSpecificData = {} }: any) {
const rawBaseUrl = normalizeBaseUrl(providerSpecificData.baseUrl) || SAP_DEFAULT_BASE_URL;
const resourceGroup = getSapResourceGroup(providerSpecificData);
const headers = applyCustomUserAgent(
{
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
"AI-Resource-Group": resourceGroup,
},
providerSpecificData
);
try {
const response = await validationRead(buildSapModelsUrl(rawBaseUrl), {
method: "GET",
headers,
});
if (response.ok) {
return { valid: true, error: null, method: "sap_models" };
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status === 429) {
return {
valid: true,
error: null,
method: "sap_models",
warning: "Rate limited, but credentials are valid",
};
}
} catch {
// Fall through to deployment probe when the discovery API is unavailable.
}
const canProbeChat =
isSapDeploymentUrl(rawBaseUrl) || /\/chat\/completions$/i.test(normalizeBaseUrl(rawBaseUrl));
if (!canProbeChat) {
return {
valid: false,
error:
"SAP validation needs either a reachable AI_API_URL or a deployment URL in providerSpecificData.baseUrl",
};
}
const validationModelId =
typeof providerSpecificData.validationModelId === "string" &&
providerSpecificData.validationModelId.trim()
? providerSpecificData.validationModelId.trim()
: "gpt-4o";
try {
const response = await validationWrite(buildSapChatUrl(rawBaseUrl), {
method: "POST",
headers,
body: JSON.stringify({
model: validationModelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
});
if (
response.ok ||
response.status === 400 ||
response.status === 404 ||
response.status === 422 ||
response.status === 429
) {
return {
valid: true,
error: null,
method: "sap_chat_probe",
...(response.status === 404
? { warning: "SAP credentials are valid, but the deployment URL or model was not found." }
: {}),
};
}
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
} catch (error: any) {
return toValidationErrorResult(error);
}
return { valid: false, error: "Connection failed while testing SAP Generative AI Hub" };
}

View File

@@ -0,0 +1,47 @@
// Generic "POST /chat/completions auth probe" used by several provider validators (command-code,
// nlpcloud + the enterprise-cloud validators). Extracted from validation.ts (god-file decomposition)
// into its own leaf so both the host dispatcher and validation/cloudProviders.ts can share it without
// a cycle. Behavior is byte-identical to the original inline def.
import { applyCustomUserAgent } from "./headers";
import { toValidationErrorResult, validationWrite } from "./transport";
export async function validateDirectChatProvider({
url,
headers,
body,
providerSpecificData = {},
isLocal = false,
}: any) {
try {
const response = await validationWrite(
url,
{
method: "POST",
headers: applyCustomUserAgent(headers, providerSpecificData),
body: JSON.stringify(body),
},
isLocal
);
if (response.status === 401 || response.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (
response.ok ||
response.status === 400 ||
response.status === 422 ||
response.status === 429
) {
return { valid: true, error: null };
}
if (response.status >= 500) {
return { valid: false, error: `Provider unavailable (${response.status})` };
}
return { valid: false, error: `Validation failed: ${response.status}` };
} catch (error: any) {
return toValidationErrorResult(error);
}
}

View File

@@ -0,0 +1,38 @@
// Characterization of the validation.ts enterprise-cloud split (god-file decomposition): the 10 cloud
// validators (heroku/databricks/datarobot/snowflake/gigachat/azure-openai/azure-ai/watsonx/oci/sap)
// moved into validation/cloudProviders.ts, and the shared "POST /chat/completions auth probe"
// (validateDirectChatProvider) moved into validation/directChatProbe.ts so the host and the cloud
// module share it without a cycle. Behavior-preserving move — the locks here are module surface +
// the no-cycle wiring. Runtime behavior stays covered by provider-validation-azure-vertex/branches.
import { test } from "node:test";
import assert from "node:assert/strict";
const cloud = await import("../../src/lib/providers/validation/cloudProviders.ts");
const probe = await import("../../src/lib/providers/validation/directChatProbe.ts");
const HOST = await import("../../src/lib/providers/validation.ts");
test("cloudProviders exposes the ten enterprise-cloud validators", () => {
for (const name of [
"validateHerokuProvider",
"validateDatabricksProvider",
"validateDataRobotProvider",
"validateSnowflakeProvider",
"validateGigachatProvider",
"validateAzureOpenAIProvider",
"validateAzureAiProvider",
"validateWatsonxProvider",
"validateOciProvider",
"validateSapProvider",
]) {
assert.equal(typeof (cloud as Record<string, unknown>)[name], "function", `missing ${name}`);
}
});
test("directChatProbe exposes the shared validateDirectChatProvider helper", () => {
assert.equal(typeof probe.validateDirectChatProvider, "function");
});
test("host dispatcher surface stays intact after the move", () => {
assert.equal(typeof (HOST as Record<string, unknown>).validateProviderApiKey, "function");
assert.equal(typeof (HOST as Record<string, unknown>).validateCommandCodeProvider, "function");
});