Skip to content

fix(config): add separate siliconflow_cn provider config field with fallback#2895

Open
idling11 wants to merge 1 commit into
Hmbown:mainfrom
idling11:fix/siliconflow-cn-provider-config
Open

fix(config): add separate siliconflow_cn provider config field with fallback#2895
idling11 wants to merge 1 commit into
Hmbown:mainfrom
idling11:fix/siliconflow-cn-provider-config

Conversation

@idling11

@idling11 idling11 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

The ProviderKind::SiliconflowCN variant existed but mapped to the same
[providers.siliconflow] TOML section — setting only [providers.siliconflow-CN]
was silently ignored.

Changes:

  • ProvidersToml / ProvidersConfig: add siliconflow_cn field with
    #[serde(alias = "siliconflow-CN")] so both sections work independently
  • for_provider() / for_provider_mut() / provider_config_for(): route
    SiliconflowCN to the new field instead of sharing siliconflow
  • resolve_runtime_options_with_secrets(): add fallback chain —
    siliconflow_cnsiliconflow for api_key / base_url / model
  • deepseek_api_key() / deepseek_base_url() / default_model(): same
    fallback on the TUI side
  • save_api_key_for(): write SiliconflowCN keys to [providers.siliconflow-CN]
  • config.example.toml: add [providers.siliconflow-CN] section with docs

Close #2893

Testing

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features
  • cargo test --workspace --all-features

Checklist

  • Updated docs or comments as needed
  • Added or updated tests where relevant
  • Verified TUI behavior manually if UI changes

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

Thanks @idling11 for taking the time to contribute.

This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this pull request is staying open. When enforcement is enabled, pull requests from contributors who are not listed in .github/APPROVED_CONTRIBUTORS will be closed automatically.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant PR access by commenting /lgtm on a pull request.

@greptile-apps greptile-apps Bot left a comment

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.

idling11 has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces support for the SiliconFlow China-hosted DeepSeek V4 (siliconflow-CN) provider, implementing fallback logic to the standard siliconflow configuration for unset fields. Feedback on the changes highlights critical compilation issues due to the use of the unstable let_chains feature on stable Rust. Additionally, the reviewer suggests adding lowercase siliconflow-cn deserialization aliases for robustness and refactoring the fallback resolution in crates/config to pre-resolve configuration values, which would significantly simplify downstream logic.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/config/src/lib.rs Outdated
#[serde(default)]
pub siliconflow: ProviderConfigToml,
#[serde(default)]
#[serde(alias = "siliconflow-CN", alias = "siliconflow_cn")]

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.

high

Since the codebase uses both siliconflow-CN (uppercase) and siliconflow-cn (lowercase) in various places (e.g., in save_api_key_for and CLI commands), we should add siliconflow-cn as an alias to ensure robust deserialization regardless of the case used in the TOML file.

    #[serde(alias = "siliconflow-CN", alias = "siliconflow-cn", alias = "siliconflow_cn")]

Comment thread crates/tui/src/config.rs Outdated
pub fireworks: ProviderConfig,
#[serde(default)]
pub siliconflow: ProviderConfig,
#[serde(default, alias = "siliconflow-CN", alias = "siliconflow_cn")]

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.

high

Add siliconflow-cn as an alias here as well to ensure consistent case-insensitive deserialization of the provider configuration.

    #[serde(default, alias = "siliconflow-CN", alias = "siliconflow-cn", alias = "siliconflow_cn")]

Comment thread crates/tui/src/config.rs Outdated
Comment on lines +2266 to +2273
if model_from_config.is_none()
&& let ApiProvider::SiliconflowCn = provider
{
model_from_config = self
.providers
.as_ref()
.and_then(|p| p.siliconflow.model.as_deref());
}

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.

high

Using the unstable let_chains feature (&& let ...) is unnecessary here and will fail to compile on stable Rust. Since ApiProvider is a standard enum, we can use a simple == comparison instead.

        if model_from_config.is_none() && provider == ApiProvider::SiliconflowCn {
            model_from_config = self
                .providers
                .as_ref()
                .and_then(|p| p.siliconflow.model.as_deref());
        }

Comment thread crates/tui/src/config.rs Outdated
Comment on lines +2364 to +2371
if provider_base.is_none()
&& let ApiProvider::SiliconflowCn = provider
{
provider_base = self
.providers
.as_ref()
.and_then(|p| p.siliconflow.base_url.clone());
}

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.

high

Avoid using the unstable let_chains feature (&& let ...) which will fail to compile on stable Rust. Use a standard == comparison instead.

        if provider_base.is_none() && provider == ApiProvider::SiliconflowCn {
            provider_base = self
                .providers
                .as_ref()
                .and_then(|p| p.siliconflow.base_url.clone());
        }

Comment thread crates/tui/src/config.rs Outdated
Comment on lines +2518 to +2527
if let ApiProvider::SiliconflowCn = provider {
if let Some(configured) = self
.providers
.as_ref()
.and_then(|p| p.siliconflow.api_key.clone())
&& !configured.trim().is_empty()
{
return Ok(configured);
}
}

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.

high

Avoid using the unstable let_chains feature (&& !configured.trim().is_empty()) which will fail to compile on stable Rust. We can use .as_deref() and .filter() to achieve this cleanly and efficiently without unnecessary cloning.

        if provider == ApiProvider::SiliconflowCn {
            if let Some(configured) = self
                .providers
                .as_ref()
                .and_then(|p| p.siliconflow.api_key.as_deref())
                .filter(|key| !key.trim().is_empty())
            {
                return Ok(configured.to_string());
            }
        }

Comment thread crates/config/src/lib.rs Outdated
Comment on lines +1358 to +1368
let provider_cfg = self.providers.for_provider(provider);
// siliconflow-CN falls back to siliconflow for each field when unset,
// so users can configure one or both sections independently.
let siliconflow_fallback = (provider == ProviderKind::SiliconflowCN)
.then(|| self.providers.siliconflow.clone())
.map(|cfg| ProviderConfigToml {
api_key: provider_cfg.api_key.clone().or(cfg.api_key),
base_url: provider_cfg.base_url.clone().or(cfg.base_url),
model: provider_cfg.model.clone().or(cfg.model),
..provider_cfg.clone()
});

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.

medium

Instead of creating a separate siliconflow_fallback variable and performing inline fallbacks in multiple places downstream, we can clone and pre-resolve provider_cfg with the fallback values right here. This simplifies the downstream logic significantly and keeps the code clean.

        let mut provider_cfg = self.providers.for_provider(provider).clone();
        if provider == ProviderKind::SiliconflowCN {
            let fallback = &self.providers.siliconflow;
            if provider_cfg.api_key.is_none() {
                provider_cfg.api_key = fallback.api_key.clone();
            }
            if provider_cfg.base_url.is_none() {
                provider_cfg.base_url = fallback.base_url.clone();
            }
            if provider_cfg.model.is_none() {
                provider_cfg.model = fallback.model.clone();
            }
        }

Comment thread crates/config/src/lib.rs
Comment on lines 1384 to 1401
let from_file = provider_cfg.api_key.clone().or(root_deepseek_api_key);
let from_file = if let Some(ref fb) = siliconflow_fallback {
from_file.or(fb.api_key.clone())
} else {
from_file
};
let explicit_api_key_for_endpoint = cli.api_key.as_deref().or(from_file.as_deref());
let provider_base_url = if let Some(ref fb) = siliconflow_fallback {
provider_cfg.base_url.clone().or(fb.base_url.clone())
} else {
provider_cfg.base_url.clone()
};
let configured_base_url = cli
.base_url
.clone()
.or_else(|| env.base_url_for(provider))
.or_else(|| provider_cfg.base_url.clone())
.or_else(|| provider_base_url)
.or(root_deepseek_base_url);

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.

medium

With provider_cfg pre-resolved with fallback values, we can revert this block back to its original, simpler form.

        let from_file = provider_cfg.api_key.clone().or(root_deepseek_api_key);
        let explicit_api_key_for_endpoint = cli.api_key.as_deref().or(from_file.as_deref());
        let configured_base_url = cli
            .base_url
            .clone()
            .or_else(|| env.base_url_for(provider))
            .or_else(|| provider_cfg.base_url.clone())
            .or(root_deepseek_base_url);

Comment thread crates/config/src/lib.rs Outdated
Comment on lines +1475 to +1481
.or_else(|| {
provider_cfg.model.clone().or_else(|| {
siliconflow_fallback
.as_ref()
.and_then(|fb| fb.model.clone())
})
})

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.

medium

With provider_cfg pre-resolved with fallback values, we can revert this block back to its original, simpler form.

            .or_else(|| provider_cfg.model.clone())

@greptile-apps greptile-apps Bot left a comment

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.

idling11 has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

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.

idling11 has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

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.

idling11 has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

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.

idling11 has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

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.

idling11 has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@Hmbown

Hmbown commented Jun 10, 2026

Copy link
Copy Markdown
Owner

@idling11 — the separate siliconflow_cn config field with fallback fixes a real gap. It's conflicting with main after tonight's merges (including your own #2898/#2941/#2930 — thanks again). Could you rebase onto current main? Happy to review promptly.

@Hmbown

Hmbown commented Jun 10, 2026

Copy link
Copy Markdown
Owner

/lgtm

…allback (Hmbown#2893)

Split SiliconflowCN into its own [providers.siliconflow_cn] TOML section
instead of silently ignoring [providers.siliconflow-CN] config.

- ProvidersToml / ProvidersConfig: add siliconflow_cn field with serde alias
- for_provider / for_provider_mut / provider_config_for: route SiliconflowCN
  to the new field
- resolve_runtime_options_with_secrets: fallback siliconflow_cn → siliconflow
  for api_key / base_url / model when unset
- deepseek_api_key: add config-file fallback for SiliconflowCn
- provider_config_key: update metadata to "siliconflow_cn"
- save_api_key_for: write SiliconflowCn keys to providers.siliconflow_cn
- docs/PROVIDERS.md, config.example.toml, scripts/check-provider-registry.py
@idling11 idling11 force-pushed the fix/siliconflow-cn-provider-config branch from 7f323e7 to c17734b Compare June 10, 2026 04:17

@greptile-apps greptile-apps Bot left a comment

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.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

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.

siliconflow provider config error

2 participants