use super::super::*;
use super::MissionControlApp;
impl MissionControlApp {
pub(crate) fn select_model_from_text(
&mut self,
model_id: &str,
ui_state: &mut state::MissionControlState,
) {
let disabled = match crate::config::read_settings(&self.config.paths) {
Ok(settings) => crate::config::disabled_model_ids_from_settings(&settings),
Err(error) => {
ui_state.status = format!("failed to read model settings: {error}");
return;
}
};
if disabled.contains(model_id) {
ui_state.status = format!("cannot select disabled model: {model_id}");
return;
}
self.select_model(model_id, ui_state);
}
pub(crate) fn select_model(
&mut self,
model_id: &str,
ui_state: &mut state::MissionControlState,
) {
match crate::commands::runtime::switch_model_selection(
&self.config.paths,
&self.state.auth_state,
model_id,
) {
Ok(selection) => {
let provider = selection.provider;
let model = selection.model;
let notice = selection.notice;
self.state.model = model.clone();
if let Ok(refreshed) = crate::config::load_effective_provider_selection(
&self.config.paths,
&provider,
&model,
) {
self.state.auth_state = refreshed.auth_state();
self.state.config = Some(refreshed.clone());
self.config.provider = refreshed.provider.clone();
self.config.model = refreshed.model.clone();
self.config.auth = refreshed.auth.clone();
self.config.api_key = refreshed.api_key.clone();
self.config.custom_providers = refreshed.custom_providers.clone();
self.config.thinking_level = refreshed.thinking_level;
}
ui_state.provider = provider.clone();
ui_state.provider_ready = self.state.auth_state.is_ready();
ui_state.model = model.clone();
ui_state.thinking_levels = cached_thinking_levels_for_model(
&self.config.paths,
&provider,
&model,
crate::thinking::capability_scope_for_provider(
&self.config.custom_providers,
&provider,
),
);
ui_state.refresh_thinking_levels(
self.config.thinking_level,
ui_state.thinking_levels.clone(),
);
let context_window = crate::config::load_context_budget(&self.config)
.map(|budget| budget.max_tokens)
.unwrap_or_else(|_| crate::context::ContextBudget::default().max_tokens);
ui_state.update_context_window(context_window);
ui_state.status = format!("model switched to {provider}/{model}");
if let Some(notice) = notice {
ui_state.status.push_str(&format!(" ({notice})"));
}
}
Err(error) => {
let message = error.to_string();
let _ = record_session_event(
self.state.current_session.as_ref(),
&self.state.cwd,
SessionEventKind::Diagnostic,
serde_json::json!({"level":"error", "message": message}),
);
let _ = send_critical(&self.events, TuiEvent::Error(message));
}
}
}
pub(crate) fn open_model_picker(
&mut self,
ui_state: &mut state::MissionControlState,
terminal_area: ratatui::layout::Rect,
) {
if let Some(catalog) = &self.model_catalog_cache
&& catalog.notice.is_none()
{
let disabled = crate::config::read_settings(&self.config.paths)
.map(|settings| crate::config::disabled_model_ids_from_settings(&settings))
.unwrap_or_default();
ui_state.open_model_picker(
catalog.entries.clone(),
disabled,
catalog.notice.clone(),
model_picker_visible_rows(terminal_area, catalog.notice.is_some()),
);
ui_state.status = "model catalog loaded".to_string();
return;
}
ui_state.status = "loading model catalogsā¦".to_string();
self.model_catalog_loading = true;
self.pending_model_catalog_consumer =
Some(super::PendingModelCatalogConsumer::SetModelPicker);
self.next_model_catalog_request_id += 1;
let request_id = self.next_model_catalog_request_id;
ui_state.pending_model_catalog_request_id = Some(request_id);
let paths = self.config.paths.clone();
let sender = self.events.clone();
thread::spawn(move || {
let agg = crate::model_catalog::load_aggregated_catalog(
&paths,
crate::model_catalog::CachePreference::AllowStale,
);
let notice = if agg.notices.is_empty() {
None
} else {
Some(agg.notices.join("; "))
};
let visible_rows = model_picker_visible_rows(terminal_area, notice.is_some());
let result = Ok(crate::model_catalog::CatalogForUi {
entries: agg.entries,
stale: agg.stale,
notice,
});
let _ = send_critical(
&sender,
TuiEvent::ModelCatalog {
request_id,
result,
visible_rows,
},
);
});
}
}