Skip to content

feat: add China LLM providers guided login flow#1254

Open
YuanyuanMa03 wants to merge 4 commits into
claude-code-best:mainfrom
YuanyuanMa03:feat/china-llm-providers-login
Open

feat: add China LLM providers guided login flow#1254
YuanyuanMa03 wants to merge 4 commits into
claude-code-best:mainfrom
YuanyuanMa03:feat/china-llm-providers-login

Conversation

@YuanyuanMa03
Copy link
Copy Markdown
Contributor

@YuanyuanMa03 YuanyuanMa03 commented Jun 4, 2026

Summary

  • Add a guided login experience for 4 domestic (China) LLM providers in the /login command: DeepSeek, Zhipu GLM, Tongyi Qianwen, and MiMo Xiaomi
  • Each provider includes model presets with pricing (CNY), context windows, and optional Coding Plan / Token Plan integration
  • All providers are OpenAI-compatible — credentials saved as OPENAI_BASE_URL + OPENAI_API_KEY under modelType: 'openai'

New file

  • src/utils/chinaLlmProviders.ts — Provider preset configurations with types, model data, pricing, and helper functions

Modified file

  • src/components/ConsoleOAuthFlow.tsx — Added 4-step guided flow:
    1. Select provider (DeepSeek / Zhipu GLM / Tongyi Qianwen / MiMo Xiaomi)
    2. Select access mode (Pay-as-you-go vs Coding Plan, only for providers that offer one)
    3. Select model (with pricing and context window info)
    4. Enter API key (with key format hint and free tier info)

Providers

Provider Models Coding Plan
DeepSeek deepseek-v4-pro, deepseek-v4-flash No
Zhipu GLM glm-5.1, glm-4.7, glm-4.7-flash (free) Yes (Lite/Pro/Max)
Tongyi Qianwen qwen3-max, qwen3.5-plus, qwen3.5-flash Yes (Pro)
MiMo Xiaomi mimo-v2.5-pro, mimo-v2.5, mimo-v2-flash Yes (Lite/Standard/Pro/Max)

Test plan

  • Run /login and verify "China LLM Providers" option appears in the menu
  • Select each provider and verify the guided flow works end-to-end
  • Verify providers with Coding Plans show mode selection step
  • Verify API key is saved correctly to settings
  • Run bun run precheck — all checks pass

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added support for China LLM Providers with a dedicated setup flow
    • Users can now select from multiple China-based providers
    • Support for both free tier and premium coding plan options
    • Multi-step configuration wizard for provider, access mode, model, and API key setup

YuanyuanMa03 and others added 4 commits May 25, 2026 04:07
Add a guided login experience for 4 domestic (China) LLM providers
in the /login command: DeepSeek, Zhipu GLM, Tongyi Qianwen, and
MiMo Xiaomi. Each provider includes model presets with pricing,
context windows, and optional Coding Plan integration.

- New file: src/utils/chinaLlmProviders.ts — provider preset configs
- Modified: src/components/ConsoleOAuthFlow.tsx — 4-step guided flow
  (select provider → select mode → select model → enter API key)

All providers are OpenAI-compatible; credentials saved as
OPENAI_BASE_URL + OPENAI_API_KEY under modelType: 'openai'.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds China LLM provider support to the OAuth flow. It introduces a new utility module defining provider types and presets (including URLs and pricing), then integrates a four-step provider setup flow into the existing OAuth component for provider, mode, model, and API key selection.

Changes

China LLM Providers OAuth Integration

Layer / File(s) Summary
China provider types and presets
src/utils/chinaLlmProviders.ts
TypeScript types (ProviderModel, CodingPlanTier, ProviderPreset) and exported CHINA_LLM_PROVIDERS constant define provider base URLs, API key pages, optional coding-plan configs, and per-model token pricing and context windows. Helper functions findChinaProviderById and resolveChinaProviderBaseURL provide lookup and URL selection.
OAuth state and option integration
src/components/ConsoleOAuthFlow.tsx (lines 22, 69–72, 463–471, 551–553)
Imports China provider helpers, extends OAuthStatus union with four new China-specific steps, adds "China LLM Providers" as a login method option in the selection list, and wires the option click handler to log analytics and initialize the China provider selection flow.
Multi-step China provider OAuth UI
src/components/ConsoleOAuthFlow.tsx (lines 1292–1482)
Implements provider selection, access-mode selection, model selection with dynamic per-model pricing labels and tags, and API key entry with validation; persists settings via updateSettingsForSource, resolves base URL, copies env into process.env, logs success, and transitions to completion; includes "confirm:no" keybinding for returning to model selection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit hops through providers bright,
China LLM flows—a setup flight!
From models to keys, step by step,
OAuth dreams in configs kept. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a guided login flow for China LLM providers. It is concise, specific, and clearly reflects the primary objective of the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/components/ConsoleOAuthFlow.tsx (2)

22-22: ⚡ Quick win

Use the src/* alias for the new provider import.

This adds another relative import inside src/, which goes against the repo import-path rule and makes future file moves harder.

Suggested change
-import { CHINA_LLM_PROVIDERS, type ProviderPreset, resolveChinaProviderBaseURL } from '../utils/chinaLlmProviders.js';
+import {
+  CHINA_LLM_PROVIDERS,
+  type ProviderPreset,
+  resolveChinaProviderBaseURL,
+} from 'src/utils/chinaLlmProviders.js';

As per coding guidelines "Import paths must use the src/* alias (e.g., import { ... } from 'src/utils/...'); tsconfig maps src/* to ./src/*."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ConsoleOAuthFlow.tsx` at line 22, Replace the relative import
in ConsoleOAuthFlow.tsx with the repo alias import: update the import that
currently pulls CHINA_LLM_PROVIDERS, ProviderPreset, and
resolveChinaProviderBaseURL via a relative path to use the src/* alias (e.g.,
import { CHINA_LLM_PROVIDERS, type ProviderPreset, resolveChinaProviderBaseURL }
from 'src/utils/chinaLlmProviders.js') so the module resolution follows the
tsconfig mapping and avoids future breakage when files move.

1425-1428: ⚡ Quick win

Don't reintroduce as any in the new src/ save path.

The China flow bypasses the settings payload type right at the persistence boundary. doOpenAISave in this same file already shows the typed pattern to reuse here.

As per coding guidelines "Do not use as any in production code; use as unknown as SpecificType for double assertions or use proper interface definitions."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ConsoleOAuthFlow.tsx` around lines 1425 - 1428, The call to
updateSettingsForSource in ConsoleOAuthFlow.tsx is bypassing types with "as
any"; replace that with the same typed pattern used by doOpenAISave: construct a
properly typed payload (or cast via as unknown as YourSettingsType) and pass
that instead of using "as any", referencing updateSettingsForSource and
doOpenAISave to mirror the typed save path and ensure the modelType/env object
conforms to the expected settings interface.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ConsoleOAuthFlow.tsx`:
- Around line 1418-1437: The saved env is merged so an existing OPENAI_AUTH_MODE
can persist; when switching to provider API keys you must explicitly clear it:
add OPENAI_AUTH_MODE: undefined to the env object you pass into
updateSettingsForSource (the env declared before the call to
updateSettingsForSource) so persisted settings remove that key, and after a
successful save also delete process.env.OPENAI_AUTH_MODE (or set it to
undefined) in the success branch where you copy env into process.env to ensure
the in-memory env is cleared as well.
- Around line 1456-1459: The help text always uses provider.apiKeyPage and
provider.keyFormat which is wrong for coding-plan providers (e.g., Qwen, MiMo);
update the rendering in ConsoleOAuthFlow.tsx so the Text nodes that currently
reference provider.apiKeyPage and provider.keyFormat instead first check for and
use the coding-plan metadata for the selected provider (e.g., locate the
provider's plan with id 'coding-plan' or a codingPlan/metadata field on the
provider and read its apiKeyPage/keyFormat) and only fall back to
provider.apiKeyPage/provider.keyFormat if that metadata is absent; update the
three Text lines near the Box flexDirection="column" block to prefer coding-plan
metadata to ensure correct key page and format are shown.

---

Nitpick comments:
In `@src/components/ConsoleOAuthFlow.tsx`:
- Line 22: Replace the relative import in ConsoleOAuthFlow.tsx with the repo
alias import: update the import that currently pulls CHINA_LLM_PROVIDERS,
ProviderPreset, and resolveChinaProviderBaseURL via a relative path to use the
src/* alias (e.g., import { CHINA_LLM_PROVIDERS, type ProviderPreset,
resolveChinaProviderBaseURL } from 'src/utils/chinaLlmProviders.js') so the
module resolution follows the tsconfig mapping and avoids future breakage when
files move.
- Around line 1425-1428: The call to updateSettingsForSource in
ConsoleOAuthFlow.tsx is bypassing types with "as any"; replace that with the
same typed pattern used by doOpenAISave: construct a properly typed payload (or
cast via as unknown as YourSettingsType) and pass that instead of using "as
any", referencing updateSettingsForSource and doOpenAISave to mirror the typed
save path and ensure the modelType/env object conforms to the expected settings
interface.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91a46235-d775-4aa1-9dc9-e8cedb4c4947

📥 Commits

Reviewing files that changed from the base of the PR and between d8892f1 and dc90f0d.

📒 Files selected for processing (2)
  • src/components/ConsoleOAuthFlow.tsx
  • src/utils/chinaLlmProviders.ts

Comment on lines +1418 to +1437
const env: Record<string, string> = {
OPENAI_BASE_URL: baseUrl,
OPENAI_API_KEY: chinaKeyValue.trim(),
OPENAI_DEFAULT_SONNET_MODEL: modelId,
OPENAI_DEFAULT_HAIKU_MODEL: modelId,
OPENAI_DEFAULT_OPUS_MODEL: modelId,
};
const { error } = updateSettingsForSource('userSettings', {
modelType: 'openai' as any,
env,
} as any);
if (error) {
setOAuthStatus({
state: 'error',
message: 'Failed to save settings. Please try again.',
toRetry: { state: 'china_apikey', provider, mode: accessMode, modelId, apiKey: chinaKeyValue },
});
} else {
for (const [k, v] of Object.entries(env)) process.env[k] = v;
logEvent('tengu_china_login_success', {});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear stale OPENAI_AUTH_MODE when switching to provider API keys.

updateSettingsForSource merges env objects, so a previous OPENAI_AUTH_MODE=chatgpt survives this write unless you explicitly send undefined. That leaves the persisted China-provider config in the wrong auth mode. The neighboring openai_chat_api save path already handles this correctly.

Suggested change
-        const env: Record<string, string> = {
+        const env: Record<string, string | undefined> = {
+          OPENAI_AUTH_MODE: undefined,
           OPENAI_BASE_URL: baseUrl,
           OPENAI_API_KEY: chinaKeyValue.trim(),
           OPENAI_DEFAULT_SONNET_MODEL: modelId,
           OPENAI_DEFAULT_HAIKU_MODEL: modelId,
           OPENAI_DEFAULT_OPUS_MODEL: modelId,
         };
@@
-          for (const [k, v] of Object.entries(env)) process.env[k] = v;
+          for (const [k, v] of Object.entries(env)) {
+            if (v === undefined) {
+              delete process.env[k];
+            } else {
+              process.env[k] = v;
+            }
+          }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const env: Record<string, string> = {
OPENAI_BASE_URL: baseUrl,
OPENAI_API_KEY: chinaKeyValue.trim(),
OPENAI_DEFAULT_SONNET_MODEL: modelId,
OPENAI_DEFAULT_HAIKU_MODEL: modelId,
OPENAI_DEFAULT_OPUS_MODEL: modelId,
};
const { error } = updateSettingsForSource('userSettings', {
modelType: 'openai' as any,
env,
} as any);
if (error) {
setOAuthStatus({
state: 'error',
message: 'Failed to save settings. Please try again.',
toRetry: { state: 'china_apikey', provider, mode: accessMode, modelId, apiKey: chinaKeyValue },
});
} else {
for (const [k, v] of Object.entries(env)) process.env[k] = v;
logEvent('tengu_china_login_success', {});
const env: Record<string, string | undefined> = {
OPENAI_AUTH_MODE: undefined,
OPENAI_BASE_URL: baseUrl,
OPENAI_API_KEY: chinaKeyValue.trim(),
OPENAI_DEFAULT_SONNET_MODEL: modelId,
OPENAI_DEFAULT_HAIKU_MODEL: modelId,
OPENAI_DEFAULT_OPUS_MODEL: modelId,
};
const { error } = updateSettingsForSource('userSettings', {
modelType: 'openai' as any,
env,
} as any);
if (error) {
setOAuthStatus({
state: 'error',
message: 'Failed to save settings. Please try again.',
toRetry: { state: 'china_apikey', provider, mode: accessMode, modelId, apiKey: chinaKeyValue },
});
} else {
for (const [k, v] of Object.entries(env)) {
if (v === undefined) {
delete process.env[k];
} else {
process.env[k] = v;
}
}
logEvent('tengu_china_login_success', {});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ConsoleOAuthFlow.tsx` around lines 1418 - 1437, The saved env
is merged so an existing OPENAI_AUTH_MODE can persist; when switching to
provider API keys you must explicitly clear it: add OPENAI_AUTH_MODE: undefined
to the env object you pass into updateSettingsForSource (the env declared before
the call to updateSettingsForSource) so persisted settings remove that key, and
after a successful save also delete process.env.OPENAI_AUTH_MODE (or set it to
undefined) in the success branch where you copy env into process.env to ensure
the in-memory env is cleared as well.

Comment on lines +1456 to +1459
<Box flexDirection="column" gap={0}>
<Text dimColor> Get your key: {provider.apiKeyPage}</Text>
<Text dimColor> {provider.freeTier}</Text>
<Text dimColor> Key format: {provider.keyFormat}</Text>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use coding-plan metadata in the coding-plan key step.

This help text always shows provider.apiKeyPage and provider.keyFormat. For coding-plan users that is wrong for at least Qwen (sk-sp-...) and MiMo (tp-..., different page), so the guided flow points users at the wrong credentials.

Suggested change
+      const keyPage =
+        accessMode === 'coding-plan' && provider.codingPlan
+          ? provider.codingPlan.purchasePage
+          : provider.apiKeyPage;
+      const keyFormat =
+        accessMode === 'coding-plan' && provider.codingPlan
+          ? provider.codingPlan.keyFormat
+          : provider.keyFormat;
@@
-            <Text dimColor> Get your key: {provider.apiKeyPage}</Text>
-            <Text dimColor> {provider.freeTier}</Text>
-            <Text dimColor> Key format: {provider.keyFormat}</Text>
+            <Text dimColor> Get your key: {keyPage}</Text>
+            <Text dimColor>
+              {accessMode === 'coding-plan' ? 'Use your Coding Plan credential here' : provider.freeTier}
+            </Text>
+            <Text dimColor> Key format: {keyFormat}</Text>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Box flexDirection="column" gap={0}>
<Text dimColor> Get your key: {provider.apiKeyPage}</Text>
<Text dimColor> {provider.freeTier}</Text>
<Text dimColor> Key format: {provider.keyFormat}</Text>
<Box flexDirection="column" gap={0}>
const keyPage =
accessMode === 'coding-plan' && provider.codingPlan
? provider.codingPlan.purchasePage
: provider.apiKeyPage;
const keyFormat =
accessMode === 'coding-plan' && provider.codingPlan
? provider.codingPlan.keyFormat
: provider.keyFormat;
<Text dimColor> Get your key: {keyPage}</Text>
<Text dimColor>
{accessMode === 'coding-plan' ? 'Use your Coding Plan credential here' : provider.freeTier}
</Text>
<Text dimColor> Key format: {keyFormat}</Text>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ConsoleOAuthFlow.tsx` around lines 1456 - 1459, The help text
always uses provider.apiKeyPage and provider.keyFormat which is wrong for
coding-plan providers (e.g., Qwen, MiMo); update the rendering in
ConsoleOAuthFlow.tsx so the Text nodes that currently reference
provider.apiKeyPage and provider.keyFormat instead first check for and use the
coding-plan metadata for the selected provider (e.g., locate the provider's plan
with id 'coding-plan' or a codingPlan/metadata field on the provider and read
its apiKeyPage/keyFormat) and only fall back to
provider.apiKeyPage/provider.keyFormat if that metadata is absent; update the
three Text lines near the Box flexDirection="column" block to prefer coding-plan
metadata to ensure correct key page and format are shown.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant