diff --git a/src/components/ConsoleOAuthFlow.tsx b/src/components/ConsoleOAuthFlow.tsx index f727ca5f2..b33b37b7d 100644 --- a/src/components/ConsoleOAuthFlow.tsx +++ b/src/components/ConsoleOAuthFlow.tsx @@ -19,6 +19,7 @@ import { getOauthAccountInfo, validateForceLoginOrg } from '../utils/auth.js'; import { openBrowser } from '../utils/browser.js'; import { logError } from '../utils/log.js'; import { getSettings_DEPRECATED, updateSettingsForSource } from '../utils/settings/settings.js'; +import { CHINA_LLM_PROVIDERS, type ProviderPreset, resolveChinaProviderBaseURL } from 'src/utils/chinaLlmProviders.js'; import { Select } from './CustomSelect/select.js'; import { Spinner } from './Spinner.js'; import TextInput from './TextInput.js'; @@ -65,6 +66,10 @@ type OAuthStatus = opusModel: string; activeField: 'base_url' | 'api_key' | 'haiku_model' | 'sonnet_model' | 'opus_model'; } // Gemini Generate Content API platform + | { state: 'china_provider_select'; activeIndex: number } // China LLM: pick provider + | { state: 'china_mode_select'; provider: ProviderPreset; activeIndex: number } // China LLM: pick access mode + | { state: 'china_model_select'; provider: ProviderPreset; mode: 'api' | 'coding-plan'; activeIndex: number } // China LLM: pick model + | { state: 'china_apikey'; provider: ProviderPreset; mode: 'api' | 'coding-plan'; modelId: string; apiKey: string } // China LLM: enter API key | { state: 'ready_to_start' } // Flow started, waiting for browser to open | { state: 'waiting_for_login'; url: string } // Browser opened, waiting for user to login | { state: 'creating_api_key' } // Got access token, creating API key @@ -457,6 +462,15 @@ function OAuthStatusMessage({ ), value: 'openai_chat_api', }, + { + label: ( + + China LLM Providers · DeepSeek, Zhipu GLM, Qwen, MiMo + {'\n'} + + ), + value: 'china_providers', + }, { label: ( @@ -536,6 +550,9 @@ function OAuthStatusMessage({ opusModel: process.env.OPENAI_DEFAULT_OPUS_MODEL ?? '', activeField: 'base_url', }); + } else if (value === 'china_providers') { + logEvent('tengu_china_providers_selected', {}); + setOAuthStatus({ state: 'china_provider_select', activeIndex: 0 }); } else if (value === 'chatgpt_subscription') { logEvent('tengu_chatgpt_subscription_selected', {}); setOAuthStatus({ @@ -1274,6 +1291,274 @@ function OAuthStatusMessage({ ); } + case 'china_provider_select': { + return ( + + Select China LLM Provider + Direct connection, no proxy needed. All providers are OpenAI-compatible. + + ({ + label: ( + + {m.label} · {m.desc} + {'\n'} + + ), + value: m.id, + }))} + onChange={value => { + logEvent('tengu_china_mode_selected', {}); + setOAuthStatus({ + state: 'china_model_select', + provider, + mode: value as 'api' | 'coding-plan', + activeIndex: 0, + }); + }} + /> + + + No plan? Select "Pay-as-you-go" + {provider.id === 'zhipu' ? ' · GLM-4.7-Flash is free forever' : ''} + + + ); + } + + case 'china_model_select': { + const { provider, mode: accessMode } = oauthStatus; + const models = provider.models; + return ( + + + {provider.icon} {provider.label} — Select Model + + +