/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import React, { useState } from 'react'; import { Box, Text, useInput } from 'ink'; import { Colors } from '../colors.js'; import { RadioButtonSelect } from './shared/RadioButtonSelect.js'; import { LoadedSettings, SettingScope } from '../../config/settings.js'; import { AuthType } from '@qwen-code/qwen-code-core'; import { validateAuthMethod, setOpenAIApiKey, setOpenAIBaseUrl, setOpenAIModel, } from '../../config/auth.js'; import { OpenAIKeyPrompt } from './OpenAIKeyPrompt.js'; interface AuthDialogProps { onSelect: (authMethod: AuthType | undefined, scope: SettingScope) => void; settings: LoadedSettings; initialErrorMessage?: string | null; } function parseDefaultAuthType( defaultAuthType: string | undefined, ): AuthType | null { if ( defaultAuthType && Object.values(AuthType).includes(defaultAuthType as AuthType) ) { return defaultAuthType as AuthType; } return null; } export function AuthDialog({ onSelect, settings, initialErrorMessage, }: AuthDialogProps): React.JSX.Element { const [errorMessage, setErrorMessage] = useState( initialErrorMessage || null, ); const [showOpenAIKeyPrompt, setShowOpenAIKeyPrompt] = useState(false); const items = [ { label: 'Qwen OAuth', value: AuthType.QWEN_OAUTH }, { label: 'OpenAI', value: AuthType.USE_OPENAI }, ]; const initialAuthIndex = Math.max( 0, items.findIndex((item) => { if (settings.merged.selectedAuthType) { return item.value === settings.merged.selectedAuthType; } const defaultAuthType = parseDefaultAuthType( process.env.GEMINI_DEFAULT_AUTH_TYPE, ); if (defaultAuthType) { return item.value === defaultAuthType; } if (process.env.GEMINI_API_KEY) { return item.value === AuthType.USE_GEMINI; } if (process.env.QWEN_OAUTH_TOKEN) { return item.value === AuthType.QWEN_OAUTH; } return item.value === AuthType.LOGIN_WITH_GOOGLE; }), ); const handleAuthSelect = (authMethod: AuthType) => { const error = validateAuthMethod(authMethod); if (error) { if (authMethod === AuthType.USE_OPENAI && !process.env.OPENAI_API_KEY) { setShowOpenAIKeyPrompt(true); setErrorMessage(null); } else { setErrorMessage(error); } } else { setErrorMessage(null); onSelect(authMethod, SettingScope.User); } }; const handleOpenAIKeySubmit = ( apiKey: string, baseUrl: string, model: string, ) => { setOpenAIApiKey(apiKey); setOpenAIBaseUrl(baseUrl); setOpenAIModel(model); setShowOpenAIKeyPrompt(false); onSelect(AuthType.USE_OPENAI, SettingScope.User); }; const handleOpenAIKeyCancel = () => { setShowOpenAIKeyPrompt(false); setErrorMessage('OpenAI API key is required to use OpenAI authentication.'); }; useInput((_input, key) => { if (showOpenAIKeyPrompt) { return; } if (key.escape) { // Prevent exit if there is an error message. // This means they user is not authenticated yet. if (errorMessage) { return; } if (settings.merged.selectedAuthType === undefined) { // Prevent exiting if no auth method is set setErrorMessage( 'You must select an auth method to proceed. Press Ctrl+C twice to exit.', ); return; } onSelect(undefined, SettingScope.User); } }); if (showOpenAIKeyPrompt) { return ( ); } return ( Get started How would you like to authenticate for this project? {errorMessage && ( {errorMessage} )} (Use Enter to Set Auth) Terms of Services and Privacy Notice for Qwen Code {'https://github.com/QwenLM/Qwen3-Coder/blob/main/README.md'} ); }