This commit is contained in:
Ahmed Ibrahim
2026-01-05 10:54:56 -08:00
parent 0239053ad9
commit dbd5c6a557
4 changed files with 145 additions and 111 deletions

View File

@@ -182,70 +182,26 @@ impl App {
let app_event_tx = AppEventSender::new(app_event_tx);
let mut config = config;
let pending_model_migration_notice =
crate::model_migration::maybe_show_pending_model_migration_notice(&config);
let conversation_manager = Arc::new(ConversationManager::new(
auth_manager.clone(),
SessionSource::Cli,
));
if let Some(notice) = &pending_model_migration_notice {
let outcome = crate::model_migration::run_startup_model_migration_prompt(
if matches!(
crate::model_migration::maybe_run_startup_model_migration_prompt(
tui,
&config,
&mut config,
conversation_manager.get_models_manager().as_ref(),
notice,
)
.await?;
match outcome {
crate::model_migration::ModelMigrationOutcome::Accepted => {
config.model = Some(notice.to_model.clone());
config
.notices
.model_migrations
.insert(notice.from_model.clone(), notice.to_model.clone());
let edits = ConfigEditsBuilder::new(&config.codex_home)
.record_model_migration_seen(
notice.from_model.as_str(),
notice.to_model.as_str(),
)
.set_model(config.model.as_deref(), config.model_reasoning_effort);
if let Err(err) = edits.apply().await {
tracing::error!(
error = %err,
"failed to persist model migration prompt outcome"
);
}
}
crate::model_migration::ModelMigrationOutcome::Rejected => {
config
.notices
.model_migrations
.insert(notice.from_model.clone(), notice.to_model.clone());
let edits = ConfigEditsBuilder::new(&config.codex_home)
.record_model_migration_seen(
notice.from_model.as_str(),
notice.to_model.as_str(),
);
if let Err(err) = edits.apply().await {
tracing::error!(
error = %err,
"failed to persist model migration prompt outcome"
);
}
}
crate::model_migration::ModelMigrationOutcome::Exit => {
return Ok(AppExitInfo {
token_usage: TokenUsage::default(),
conversation_id: None,
update_action: None,
});
}
}
.await?,
crate::model_migration::StartupModelMigrationAction::Exit
) {
return Ok(AppExitInfo {
token_usage: TokenUsage::default(),
conversation_id: None,
update_action: None,
});
}
let enhanced_keys_supported = tui.enhanced_keys_supported();

View File

@@ -1,4 +1,6 @@
use codex_core::config::Config;
use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::models_manager::manager::ModelsManager;
use codex_core::models_manager::model_presets::HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG;
use codex_core::models_manager::model_presets::HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG;
use codex_protocol::openai_models::ModelPreset;
@@ -26,6 +28,11 @@ pub(crate) use prompt_ui::ModelMigrationOutcome;
pub(crate) use prompt_ui::ModelMigrationScreen;
pub(crate) use prompt_ui::migration_copy_for_models;
pub(crate) enum StartupModelMigrationAction {
Continue,
Exit,
}
/// Read the pending migration notice file, returning the notice if it should be shown.
pub(crate) fn maybe_show_pending_model_migration_notice(
config: &Config,
@@ -79,6 +86,60 @@ pub(crate) fn maybe_show_pending_model_migration_notice(
Some(notice)
}
pub(crate) async fn maybe_run_startup_model_migration_prompt(
tui: &mut crate::tui::Tui,
config: &mut Config,
models_manager: &ModelsManager,
) -> Result<StartupModelMigrationAction> {
let pending_model_migration_notice = maybe_show_pending_model_migration_notice(config);
let Some(notice) = &pending_model_migration_notice else {
return Ok(StartupModelMigrationAction::Continue);
};
let outcome = run_startup_model_migration_prompt(tui, config, models_manager, notice).await?;
match outcome {
ModelMigrationOutcome::Accepted => {
config.model = Some(notice.to_model.clone());
config
.notices
.model_migrations
.insert(notice.from_model.clone(), notice.to_model.clone());
let edits = ConfigEditsBuilder::new(&config.codex_home)
.record_model_migration_seen(notice.from_model.as_str(), notice.to_model.as_str())
.set_model(config.model.as_deref(), config.model_reasoning_effort);
if let Err(err) = edits.apply().await {
tracing::error!(
error = %err,
"failed to persist model migration prompt outcome"
);
}
Ok(StartupModelMigrationAction::Continue)
}
ModelMigrationOutcome::Rejected => {
config
.notices
.model_migrations
.insert(notice.from_model.clone(), notice.to_model.clone());
let edits = ConfigEditsBuilder::new(&config.codex_home)
.record_model_migration_seen(notice.from_model.as_str(), notice.to_model.as_str());
if let Err(err) = edits.apply().await {
tracing::error!(
error = %err,
"failed to persist model migration prompt outcome"
);
}
Ok(StartupModelMigrationAction::Continue)
}
ModelMigrationOutcome::Exit => Ok(StartupModelMigrationAction::Exit),
}
}
/// Persist the migration notice for the next startup, replacing any existing scheduled notice.
///
/// Scheduling is intentionally independent of session configuration: it uses the user's config

View File

@@ -223,71 +223,27 @@ impl App {
let app_event_tx = AppEventSender::new(app_event_tx);
let mut config = config;
let pending_model_migration_notice =
crate::model_migration::maybe_show_pending_model_migration_notice(&config);
let conversation_manager = Arc::new(ConversationManager::new(
auth_manager.clone(),
SessionSource::Cli,
));
if let Some(notice) = &pending_model_migration_notice {
let outcome = crate::model_migration::run_startup_model_migration_prompt(
if matches!(
crate::model_migration::maybe_run_startup_model_migration_prompt(
tui,
&config,
&mut config,
conversation_manager.get_models_manager().as_ref(),
notice,
)
.await?;
match outcome {
crate::model_migration::ModelMigrationOutcome::Accepted => {
config.model = Some(notice.to_model.clone());
config
.notices
.model_migrations
.insert(notice.from_model.clone(), notice.to_model.clone());
let edits = ConfigEditsBuilder::new(&config.codex_home)
.record_model_migration_seen(
notice.from_model.as_str(),
notice.to_model.as_str(),
)
.set_model(config.model.as_deref(), config.model_reasoning_effort);
if let Err(err) = edits.apply().await {
tracing::error!(
error = %err,
"failed to persist model migration prompt outcome"
);
}
}
crate::model_migration::ModelMigrationOutcome::Rejected => {
config
.notices
.model_migrations
.insert(notice.from_model.clone(), notice.to_model.clone());
let edits = ConfigEditsBuilder::new(&config.codex_home)
.record_model_migration_seen(
notice.from_model.as_str(),
notice.to_model.as_str(),
);
if let Err(err) = edits.apply().await {
tracing::error!(
error = %err,
"failed to persist model migration prompt outcome"
);
}
}
crate::model_migration::ModelMigrationOutcome::Exit => {
return Ok(AppExitInfo {
token_usage: TokenUsage::default(),
conversation_id: None,
update_action: None,
session_lines: Vec::new(),
});
}
}
.await?,
crate::model_migration::StartupModelMigrationAction::Exit
) {
return Ok(AppExitInfo {
token_usage: TokenUsage::default(),
conversation_id: None,
update_action: None,
session_lines: Vec::new(),
});
}
let enhanced_keys_supported = tui.enhanced_keys_supported();

View File

@@ -1,4 +1,6 @@
use codex_core::config::Config;
use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::models_manager::manager::ModelsManager;
use codex_core::models_manager::model_presets::HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG;
use codex_core::models_manager::model_presets::HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG;
use codex_protocol::openai_models::ModelPreset;
@@ -26,6 +28,11 @@ pub(crate) use prompt_ui::ModelMigrationOutcome;
pub(crate) use prompt_ui::ModelMigrationScreen;
pub(crate) use prompt_ui::migration_copy_for_models;
pub(crate) enum StartupModelMigrationAction {
Continue,
Exit,
}
/// Read the pending migration notice file, returning the notice if it should be shown.
pub(crate) fn maybe_show_pending_model_migration_notice(
config: &Config,
@@ -79,6 +86,60 @@ pub(crate) fn maybe_show_pending_model_migration_notice(
Some(notice)
}
pub(crate) async fn maybe_run_startup_model_migration_prompt(
tui: &mut crate::tui::Tui,
config: &mut Config,
models_manager: &ModelsManager,
) -> Result<StartupModelMigrationAction> {
let pending_model_migration_notice = maybe_show_pending_model_migration_notice(config);
let Some(notice) = &pending_model_migration_notice else {
return Ok(StartupModelMigrationAction::Continue);
};
let outcome = run_startup_model_migration_prompt(tui, config, models_manager, notice).await?;
match outcome {
ModelMigrationOutcome::Accepted => {
config.model = Some(notice.to_model.clone());
config
.notices
.model_migrations
.insert(notice.from_model.clone(), notice.to_model.clone());
let edits = ConfigEditsBuilder::new(&config.codex_home)
.record_model_migration_seen(notice.from_model.as_str(), notice.to_model.as_str())
.set_model(config.model.as_deref(), config.model_reasoning_effort);
if let Err(err) = edits.apply().await {
tracing::error!(
error = %err,
"failed to persist model migration prompt outcome"
);
}
Ok(StartupModelMigrationAction::Continue)
}
ModelMigrationOutcome::Rejected => {
config
.notices
.model_migrations
.insert(notice.from_model.clone(), notice.to_model.clone());
let edits = ConfigEditsBuilder::new(&config.codex_home)
.record_model_migration_seen(notice.from_model.as_str(), notice.to_model.as_str());
if let Err(err) = edits.apply().await {
tracing::error!(
error = %err,
"failed to persist model migration prompt outcome"
);
}
Ok(StartupModelMigrationAction::Continue)
}
ModelMigrationOutcome::Exit => Ok(StartupModelMigrationAction::Exit),
}
}
/// Persist the migration notice for the next startup, replacing any existing scheduled notice.
///
/// Scheduling is intentionally independent of session configuration: it uses the user's config