fix: refine auth message to give explicit tip

This commit is contained in:
mingholy.lmh 2026-01-07 22:56:57 +08:00
parent ded1ebcdff
commit 5ea841dd02
9 changed files with 148 additions and 71 deletions

View file

@ -45,11 +45,19 @@ function findModelConfig(
/**
* Check if API key is available for the given auth type and model configuration.
* Prioritizes custom envKey from modelProviders over default environment variables.
*
* @returns hasKey - whether an API key is available
* @returns checkedEnvKey - the environment variable name that was checked
* @returns isExplicitEnvKey - true if model has explicit envKey configured (no apiKey fallback allowed)
*/
function hasApiKeyForAuth(
authType: string,
settings: Settings,
): { hasKey: boolean; checkedEnvKey: string | undefined } {
): {
hasKey: boolean;
checkedEnvKey: string | undefined;
isExplicitEnvKey: boolean;
} {
const modelProviders = settings.modelProviders as
| ModelProvidersConfig
| undefined;
@ -58,25 +66,64 @@ function hasApiKeyForAuth(
// Try to find model-specific envKey from modelProviders
const modelConfig = findModelConfig(modelProviders, authType, modelId);
if (modelConfig?.envKey) {
// Explicit envKey configured - only check this env var, no apiKey fallback
const hasKey = !!process.env[modelConfig.envKey];
return { hasKey, checkedEnvKey: modelConfig.envKey };
return {
hasKey,
checkedEnvKey: modelConfig.envKey,
isExplicitEnvKey: true,
};
}
// Fallback to default environment variable
// Using default environment variable - apiKey fallback is allowed
const defaultEnvKey = DEFAULT_ENV_KEYS[authType];
if (defaultEnvKey) {
const hasKey = !!process.env[defaultEnvKey];
if (hasKey) {
return { hasKey, checkedEnvKey: defaultEnvKey };
return { hasKey, checkedEnvKey: defaultEnvKey, isExplicitEnvKey: false };
}
}
// Also check settings.security.auth.apiKey as fallback
// Also check settings.security.auth.apiKey as fallback (only for default env key)
if (settings.security?.auth?.apiKey) {
return { hasKey: true, checkedEnvKey: defaultEnvKey || undefined };
return {
hasKey: true,
checkedEnvKey: defaultEnvKey || undefined,
isExplicitEnvKey: false,
};
}
return { hasKey: false, checkedEnvKey: undefined };
return {
hasKey: false,
checkedEnvKey: defaultEnvKey,
isExplicitEnvKey: false,
};
}
/**
* Generate API key error message based on auth check result.
* Returns null if API key is present, otherwise returns the appropriate error message.
*/
function getApiKeyError(authMethod: string, settings: Settings): string | null {
const { hasKey, checkedEnvKey, isExplicitEnvKey } = hasApiKeyForAuth(
authMethod,
settings,
);
if (hasKey) {
return null;
}
const envKeyHint = checkedEnvKey || DEFAULT_ENV_KEYS[authMethod];
if (isExplicitEnvKey) {
return t(
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.',
{ envKeyHint },
);
}
return t(
'{{envKeyHint}} environment variable not found (or set settings.security.auth.apiKey). Please set it in your .env file or environment variables.',
{ envKeyHint },
);
}
export function validateAuthMethod(authMethod: string): string | null {
@ -84,14 +131,22 @@ export function validateAuthMethod(authMethod: string): string | null {
loadEnvironment(settings.merged);
if (authMethod === AuthType.USE_OPENAI) {
const { hasKey, checkedEnvKey } = hasApiKeyForAuth(
const { hasKey, checkedEnvKey, isExplicitEnvKey } = hasApiKeyForAuth(
authMethod,
settings.merged,
);
if (!hasKey) {
const envKeyHint = checkedEnvKey
? `'${checkedEnvKey}'`
: "'OPENAI_API_KEY' (or configure modelProviders[].envKey)";
: "'OPENAI_API_KEY'";
if (isExplicitEnvKey) {
// Explicit envKey configured - only suggest setting the env var
return t(
'Missing API key for OpenAI-compatible auth. Set the {{envKeyHint}} environment variable.',
{ envKeyHint },
);
}
// Default env key - can use either apiKey or env var
return t(
'Missing API key for OpenAI-compatible auth. Set settings.security.auth.apiKey, or set the {{envKeyHint}} environment variable.',
{ envKeyHint },
@ -107,15 +162,9 @@ export function validateAuthMethod(authMethod: string): string | null {
}
if (authMethod === AuthType.USE_ANTHROPIC) {
const { hasKey, checkedEnvKey } = hasApiKeyForAuth(
authMethod,
settings.merged,
);
if (!hasKey) {
const envKeyHint = checkedEnvKey || 'ANTHROPIC_API_KEY';
return t('{{envKeyHint}} environment variable not found.', {
envKeyHint,
});
const apiKeyError = getApiKeyError(authMethod, settings.merged);
if (apiKeyError) {
return apiKeyError;
}
// Check baseUrl - can come from modelProviders or environment
@ -124,43 +173,31 @@ export function validateAuthMethod(authMethod: string): string | null {
| undefined;
const modelId = settings.merged.model?.name;
const modelConfig = findModelConfig(modelProviders, authMethod, modelId);
const hasBaseUrl =
modelConfig?.baseUrl || process.env['ANTHROPIC_BASE_URL'];
if (!hasBaseUrl) {
if (modelConfig && !modelConfig.baseUrl) {
return t(
'ANTHROPIC_BASE_URL environment variable not found (or configure modelProviders[].baseUrl).',
'Anthropic provider missing required baseUrl in modelProviders[].baseUrl.',
);
}
if (!modelConfig && !process.env['ANTHROPIC_BASE_URL']) {
return t('ANTHROPIC_BASE_URL environment variable not found.');
}
return null;
}
if (authMethod === AuthType.USE_GEMINI) {
const { hasKey, checkedEnvKey } = hasApiKeyForAuth(
authMethod,
settings.merged,
);
if (!hasKey) {
const envKeyHint = checkedEnvKey || 'GEMINI_API_KEY';
return t(
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.',
{ envKeyHint },
);
const apiKeyError = getApiKeyError(authMethod, settings.merged);
if (apiKeyError) {
return apiKeyError;
}
return null;
}
if (authMethod === AuthType.USE_VERTEX_AI) {
const { hasKey, checkedEnvKey } = hasApiKeyForAuth(
authMethod,
settings.merged,
);
if (!hasKey) {
const envKeyHint = checkedEnvKey || 'GOOGLE_API_KEY';
return t(
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.',
{ envKeyHint },
);
const apiKeyError = getApiKeyError(authMethod, settings.merged);
if (apiKeyError) {
return apiKeyError;
}
process.env['GOOGLE_GENAI_USE_VERTEXAI'] = 'true';