Skip to content

Commit 97cc35e

Browse files
committed
refactor: improve readability of custom provider checks in REPL
- Refactored conditional checks for custom provider base URL in the REPL implementation to enhance code clarity and maintainability. - Updated the TUI to streamline the display of custom provider options and improve user experience during provider setup. - Simplified the onboarding process by refining the handling of custom provider validation and error messages.
1 parent f2821a7 commit 97cc35e

4 files changed

Lines changed: 108 additions & 74 deletions

File tree

crates/cli/src/repl.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,15 @@ impl Repl {
415415
p: ProviderKind,
416416
out: ReplOutput<'_>,
417417
) -> anyhow::Result<()> {
418-
if p == ProviderKind::Custom && self.runtime.config().provider.custom.base_url.trim().is_empty()
418+
if p == ProviderKind::Custom
419+
&& self
420+
.runtime
421+
.config()
422+
.provider
423+
.custom
424+
.base_url
425+
.trim()
426+
.is_empty()
419427
{
420428
out.eprintln(
421429
"[provider] custom provider is not configured yet; run /provider → \"Add custom provider…\", or: /custom <openai|anthropic> <base-url> [api-key] [model]",
@@ -1858,7 +1866,14 @@ impl Repl {
18581866
}
18591867
TuiCmd::ApplyDefaultProvider(p) => {
18601868
if p == ProviderKind::Custom
1861-
&& self.runtime.config().provider.custom.base_url.trim().is_empty()
1869+
&& self
1870+
.runtime
1871+
.config()
1872+
.provider
1873+
.custom
1874+
.base_url
1875+
.trim()
1876+
.is_empty()
18621877
{
18631878
if let Ok(mut g) = tui_state.lock() {
18641879
g.open_custom_provider_setup(self.runtime.model().to_string());
@@ -1894,7 +1909,14 @@ impl Repl {
18941909
TuiCmd::PromptApiKey(p, connect_after_save) => {
18951910
if let Ok(mut g) = tui_state.lock() {
18961911
if p == ProviderKind::Custom
1897-
&& self.runtime.config().provider.custom.base_url.trim().is_empty()
1912+
&& self
1913+
.runtime
1914+
.config()
1915+
.provider
1916+
.custom
1917+
.base_url
1918+
.trim()
1919+
.is_empty()
18981920
{
18991921
g.open_custom_provider_setup(self.runtime.model().to_string());
19001922
g.blocks.push(DisplayBlock::System(

crates/cli/src/tui/app.rs

Lines changed: 75 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,18 +2106,27 @@ pub fn run_blocking(
21062106
Style::default().fg(theme::MUTED),
21072107
)));
21082108
}
2109-
for i in scroll..end {
2110-
let label = if i < n_builtin {
2111-
let p = all[i];
2112-
let name = p.display_name();
2113-
if p == ProviderKind::Custom {
2114-
format!("{name} (BYO endpoint)")
2109+
let row_labels: Vec<String> = (0..n)
2110+
.map(|i| {
2111+
if i < n_builtin {
2112+
let p = all[i];
2113+
let name = p.display_name();
2114+
if p == ProviderKind::Custom {
2115+
format!("{name} (BYO endpoint)")
2116+
} else {
2117+
name.to_string()
2118+
}
21152119
} else {
2116-
name.to_string()
2120+
"Add custom provider…".to_string()
21172121
}
2118-
} else {
2119-
"Add custom provider…".to_string()
2120-
};
2122+
})
2123+
.collect();
2124+
for (i, label) in row_labels
2125+
.iter()
2126+
.enumerate()
2127+
.skip(scroll)
2128+
.take(end.saturating_sub(scroll))
2129+
{
21212130
let st = if i == g.provider_picker_index {
21222131
Style::default()
21232132
.fg(Color::Black)
@@ -3287,72 +3296,71 @@ pub fn run_blocking(
32873296
(KeyCode::Esc, _) => {
32883297
g.close_custom_provider_setup();
32893298
}
3290-
(KeyCode::Enter, _) => {
3291-
match g.custom_provider_setup_step {
3292-
CustomProviderSetupStep::Compatibility => {
3293-
g.custom_provider_setup_step = CustomProviderSetupStep::BaseUrl;
3294-
g.custom_setup_input.clear();
3295-
}
3296-
CustomProviderSetupStep::BaseUrl => {
3297-
let t = g.custom_setup_input.trim();
3298-
if t.is_empty() {
3299-
g.push_error(
3299+
(KeyCode::Enter, _) => match g.custom_provider_setup_step {
3300+
CustomProviderSetupStep::Compatibility => {
3301+
g.custom_provider_setup_step = CustomProviderSetupStep::BaseUrl;
3302+
g.custom_setup_input.clear();
3303+
}
3304+
CustomProviderSetupStep::BaseUrl => {
3305+
let t = g.custom_setup_input.trim();
3306+
if t.is_empty() {
3307+
g.push_error(
33003308
"[custom] enter a base URL (e.g. https://api.example.com)"
33013309
.into(),
33023310
);
3303-
} else {
3304-
g.custom_setup_base_url = t.to_string();
3305-
g.custom_setup_input.clear();
3306-
g.custom_provider_setup_step =
3307-
CustomProviderSetupStep::ApiKey;
3308-
}
3311+
} else {
3312+
g.custom_setup_base_url = t.to_string();
3313+
g.custom_setup_input.clear();
3314+
g.custom_provider_setup_step =
3315+
CustomProviderSetupStep::ApiKey;
33093316
}
3310-
CustomProviderSetupStep::ApiKey => {
3311-
let t = g.custom_setup_input.trim();
3312-
if t.is_empty() {
3313-
g.push_error("[custom] API key is required".into());
3314-
} else {
3315-
g.custom_setup_api_key = t.to_string();
3316-
g.custom_setup_input = g.custom_setup_model_hint.clone();
3317-
if g.custom_setup_input.trim().is_empty() {
3318-
g.custom_setup_input = "custom-model".into();
3319-
}
3320-
g.custom_provider_setup_step =
3321-
CustomProviderSetupStep::Model;
3317+
}
3318+
CustomProviderSetupStep::ApiKey => {
3319+
let t = g.custom_setup_input.trim();
3320+
if t.is_empty() {
3321+
g.push_error("[custom] API key is required".into());
3322+
} else {
3323+
g.custom_setup_api_key = t.to_string();
3324+
g.custom_setup_input = g.custom_setup_model_hint.clone();
3325+
if g.custom_setup_input.trim().is_empty() {
3326+
g.custom_setup_input = "custom-model".into();
33223327
}
3323-
}
3324-
CustomProviderSetupStep::Model => {
3325-
let t = g.custom_setup_input.trim();
3326-
let model = if t.is_empty() {
3327-
"custom-model".to_string()
3328-
} else {
3329-
t.to_string()
3330-
};
3331-
let compatibility = if g.custom_setup_compat_index == 0 {
3332-
ProviderCompatibility::OpenAi
3333-
} else {
3334-
ProviderCompatibility::Anthropic
3335-
};
3336-
let base_url = g.custom_setup_base_url.clone();
3337-
let api_key = g.custom_setup_api_key.clone();
3338-
g.close_custom_provider_setup();
3339-
drop(g);
3340-
let _ = cmd_tx.send(TuiCmd::ApplyCustomProviderSetup {
3341-
compatibility,
3342-
base_url,
3343-
api_key,
3344-
model,
3345-
});
3328+
g.custom_provider_setup_step =
3329+
CustomProviderSetupStep::Model;
33463330
}
33473331
}
3348-
}
3332+
CustomProviderSetupStep::Model => {
3333+
let t = g.custom_setup_input.trim();
3334+
let model = if t.is_empty() {
3335+
"custom-model".to_string()
3336+
} else {
3337+
t.to_string()
3338+
};
3339+
let compatibility = if g.custom_setup_compat_index == 0 {
3340+
ProviderCompatibility::OpenAi
3341+
} else {
3342+
ProviderCompatibility::Anthropic
3343+
};
3344+
let base_url = g.custom_setup_base_url.clone();
3345+
let api_key = g.custom_setup_api_key.clone();
3346+
g.close_custom_provider_setup();
3347+
drop(g);
3348+
let _ = cmd_tx.send(TuiCmd::ApplyCustomProviderSetup {
3349+
compatibility,
3350+
base_url,
3351+
api_key,
3352+
model,
3353+
});
3354+
}
3355+
},
33493356
(KeyCode::Up, _)
33503357
if matches!(
33513358
g.custom_provider_setup_step,
33523359
CustomProviderSetupStep::Compatibility
33533360
) =>
33543361
{
3355-
g.custom_setup_compat_index = g.custom_setup_compat_index.saturating_sub(1);
3362+
g.custom_setup_compat_index =
3363+
g.custom_setup_compat_index.saturating_sub(1);
33563364
}
33573365
(KeyCode::Down, _)
33583366
if matches!(
@@ -3395,7 +3403,8 @@ pub fn run_blocking(
33953403
}
33963404
(KeyCode::Up, _) => {
33973405
if n > 0 {
3398-
g.provider_picker_index = g.provider_picker_index.saturating_sub(1);
3406+
g.provider_picker_index =
3407+
g.provider_picker_index.saturating_sub(1);
33993408
}
34003409
g.sync_provider_picker_scroll();
34013410
}
@@ -3438,7 +3447,8 @@ pub fn run_blocking(
34383447
g.open_custom_provider_setup(hint);
34393448
continue;
34403449
}
3441-
let p = ProviderKind::ALL[g.provider_picker_index.min(n_builtin - 1)];
3450+
let p =
3451+
ProviderKind::ALL[g.provider_picker_index.min(n_builtin - 1)];
34423452
g.close_provider_picker();
34433453
if for_key {
34443454
drop(g);

crates/cli/src/tui/onboarding.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ fn onboarding_connect_rows(search: &str) -> Vec<ConnectRow> {
3030
for row in build_connect_rows(search) {
3131
match row {
3232
ConnectRow::SectionHeader(label) => pending_header = Some(label),
33-
ConnectRow::Provider { kind, .. } if kind == ProviderKind::Custom => {}
33+
ConnectRow::Provider {
34+
kind: ProviderKind::Custom,
35+
..
36+
} => {}
3437
provider @ ConnectRow::Provider { .. } => {
3538
if let Some(label) = pending_header.take() {
3639
out.push(ConnectRow::SectionHeader(label));
@@ -166,10 +169,7 @@ async fn run_onboarding_inner(
166169
let vs = validation_state.clone();
167170
tokio::spawn(async move {
168171
let result = nca_core::provider::validate::validate_api_key(
169-
provider,
170-
&key_str,
171-
&base_url,
172-
None,
172+
provider, &key_str, &base_url, None,
173173
)
174174
.await;
175175
if let Ok(mut g) = vs.lock() {

crates/runtime/src/model_limits_api.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ pub async fn resolve_model_limits(config: &NcaConfig, model: &str) -> ModelLimit
139139
};
140140
let base = config.provider.custom.base_url.trim_end_matches('/');
141141
match config.provider.custom.compatibility {
142-
ProviderCompatibility::OpenAi => fetch_openai_context(&client, base, &key, model).await,
142+
ProviderCompatibility::OpenAi => {
143+
fetch_openai_context(&client, base, &key, model).await
144+
}
143145
ProviderCompatibility::Anthropic => {
144146
fetch_anthropic_context(&client, base, &key, model).await
145147
}

0 commit comments

Comments
 (0)