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

@ -149,7 +149,7 @@ describe('validateAuthMethod', () => {
process.env['CUSTOM_ANTHROPIC_KEY'] = 'custom-key';
const result = validateAuthMethod(AuthType.USE_ANTHROPIC);
expect(result).toContain('ANTHROPIC_BASE_URL');
expect(result).toContain('modelProviders[].baseUrl');
});
it('should return null for USE_VERTEX_AI with custom envKey', () => {

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';

View file

@ -798,8 +798,14 @@ export default {
'Umgebungsvariable {{envKeyHint}} wurde nicht gefunden.',
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.':
'Umgebungsvariable {{envKeyHint}} wurde nicht gefunden. Bitte legen Sie sie in Ihrer .env-Datei oder den Systemumgebungsvariablen fest.',
'ANTHROPIC_BASE_URL environment variable not found (or configure modelProviders[].baseUrl).':
'Umgebungsvariable ANTHROPIC_BASE_URL wurde nicht gefunden (oder konfigurieren Sie modelProviders[].baseUrl).',
'{{envKeyHint}} environment variable not found (or set settings.security.auth.apiKey). Please set it in your .env file or environment variables.':
'Umgebungsvariable {{envKeyHint}} wurde nicht gefunden (oder setzen Sie settings.security.auth.apiKey). Bitte legen Sie sie in Ihrer .env-Datei oder den Systemumgebungsvariablen fest.',
'Missing API key for OpenAI-compatible auth. Set the {{envKeyHint}} environment variable.':
'API-Schlüssel für OpenAI-kompatible Authentifizierung fehlt. Setzen Sie die Umgebungsvariable {{envKeyHint}}.',
'Anthropic provider missing required baseUrl in modelProviders[].baseUrl.':
'Anthropic-Anbieter fehlt erforderliche baseUrl in modelProviders[].baseUrl.',
'ANTHROPIC_BASE_URL environment variable not found.':
'Umgebungsvariable ANTHROPIC_BASE_URL wurde nicht gefunden.',
'Invalid auth method selected.':
'Ungültige Authentifizierungsmethode ausgewählt.',
'Failed to authenticate. Message: {{message}}':

View file

@ -776,8 +776,14 @@ export default {
'{{envKeyHint}} environment variable not found.',
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.':
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.',
'ANTHROPIC_BASE_URL environment variable not found (or configure modelProviders[].baseUrl).':
'ANTHROPIC_BASE_URL environment variable not found (or configure modelProviders[].baseUrl).',
'{{envKeyHint}} environment variable not found (or set settings.security.auth.apiKey). Please set it in your .env file or environment variables.':
'{{envKeyHint}} environment variable not found (or set settings.security.auth.apiKey). Please set it in your .env file or environment variables.',
'Missing API key for OpenAI-compatible auth. Set the {{envKeyHint}} environment variable.':
'Missing API key for OpenAI-compatible auth. Set the {{envKeyHint}} environment variable.',
'Anthropic provider missing required baseUrl in modelProviders[].baseUrl.':
'Anthropic provider missing required baseUrl in modelProviders[].baseUrl.',
'ANTHROPIC_BASE_URL environment variable not found.':
'ANTHROPIC_BASE_URL environment variable not found.',
'Invalid auth method selected.': 'Invalid auth method selected.',
'Failed to authenticate. Message: {{message}}':
'Failed to authenticate. Message: {{message}}',

View file

@ -792,8 +792,14 @@ export default {
'Переменная окружения {{envKeyHint}} не найдена.',
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.':
'Переменная окружения {{envKeyHint}} не найдена. Укажите её в файле .env или среди системных переменных.',
'ANTHROPIC_BASE_URL environment variable not found (or configure modelProviders[].baseUrl).':
'Переменная окружения ANTHROPIC_BASE_URL не найдена (или настройте modelProviders[].baseUrl).',
'{{envKeyHint}} environment variable not found (or set settings.security.auth.apiKey). Please set it in your .env file or environment variables.':
'Переменная окружения {{envKeyHint}} не найдена (или установите settings.security.auth.apiKey). Укажите её в файле .env или среди системных переменных.',
'Missing API key for OpenAI-compatible auth. Set the {{envKeyHint}} environment variable.':
'Отсутствует API-ключ для аутентификации, совместимой с OpenAI. Установите переменную окружения {{envKeyHint}}.',
'Anthropic provider missing required baseUrl in modelProviders[].baseUrl.':
'У провайдера Anthropic отсутствует обязательный baseUrl в modelProviders[].baseUrl.',
'ANTHROPIC_BASE_URL environment variable not found.':
'Переменная окружения ANTHROPIC_BASE_URL не найдена.',
'Invalid auth method selected.': 'Выбран недопустимый метод авторизации.',
'Failed to authenticate. Message: {{message}}':
'Не удалось авторизоваться. Сообщение: {{message}}',

View file

@ -734,8 +734,14 @@ export default {
'未找到 {{envKeyHint}} 环境变量。',
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.':
'未找到 {{envKeyHint}} 环境变量。请在 .env 文件或系统环境变量中进行设置。',
'ANTHROPIC_BASE_URL environment variable not found (or configure modelProviders[].baseUrl).':
'未找到 ANTHROPIC_BASE_URL 环境变量(或配置 modelProviders[].baseUrl。',
'{{envKeyHint}} environment variable not found (or set settings.security.auth.apiKey). Please set it in your .env file or environment variables.':
'未找到 {{envKeyHint}} 环境变量(或设置 settings.security.auth.apiKey。请在 .env 文件或系统环境变量中进行设置。',
'Missing API key for OpenAI-compatible auth. Set the {{envKeyHint}} environment variable.':
'缺少 OpenAI 兼容认证的 API 密钥。请设置 {{envKeyHint}} 环境变量。',
'Anthropic provider missing required baseUrl in modelProviders[].baseUrl.':
'Anthropic 提供商缺少必需的 baseUrl请在 modelProviders[].baseUrl 中配置。',
'ANTHROPIC_BASE_URL environment variable not found.':
'未找到 ANTHROPIC_BASE_URL 环境变量。',
'Invalid auth method selected.': '选择了无效的认证方式。',
'Failed to authenticate. Message: {{message}}': '认证失败。消息:{{message}}',
'Authenticated successfully with {{authType}} credentials.':