Use markdown for migration screen (#8952)

Next steps will be routing this to model info
This commit is contained in:
Ahmed Ibrahim
2026-01-13 07:41:42 +00:00
committed by GitHub
parent 18b737910c
commit 325ce985f1
12 changed files with 147 additions and 13 deletions
+7
View File
@@ -201,6 +201,7 @@ async fn handle_model_migration_prompt_if_needed(
migration_config_key,
model_link,
upgrade_copy,
migration_markdown,
}) = upgrade
{
if migration_prompt_hidden(config, migration_config_key.as_str()) {
@@ -234,6 +235,7 @@ async fn handle_model_migration_prompt_if_needed(
&target_model,
model_link.clone(),
upgrade_copy.clone(),
migration_markdown.clone(),
heading_label,
target_description,
can_opt_out,
@@ -1598,6 +1600,9 @@ mod tests {
fn model_migration_copy_to_plain_text(
copy: &crate::model_migration::ModelMigrationCopy,
) -> String {
if let Some(markdown) = copy.markdown.as_ref() {
return markdown.clone();
}
let mut s = String::new();
for span in &copy.heading {
s.push_str(&span.content);
@@ -1680,6 +1685,7 @@ mod tests {
migration_config_key: HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG.to_string(),
model_link: None,
upgrade_copy: None,
migration_markdown: None,
});
available.retain(|preset| preset.model != "gpt-5-codex");
available.push(current.clone());
@@ -1735,6 +1741,7 @@ mod tests {
&upgrade.id,
upgrade.model_link.clone(),
upgrade.upgrade_copy.clone(),
upgrade.migration_markdown.clone(),
target.display_name.clone(),
target_description,
can_opt_out,
+52 -3
View File
@@ -1,4 +1,5 @@
use crate::key_hint;
use crate::markdown_render::render_markdown_text_with_width;
use crate::render::Insets;
use crate::render::renderable::ColumnRenderable;
use crate::render::renderable::Renderable;
@@ -34,6 +35,7 @@ pub(crate) struct ModelMigrationCopy {
pub heading: Vec<Span<'static>>,
pub content: Vec<Line<'static>>,
pub can_opt_out: bool,
pub markdown: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -55,15 +57,30 @@ impl MigrationMenuOption {
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn migration_copy_for_models(
current_model: &str,
target_model: &str,
model_link: Option<String>,
migration_copy: Option<String>,
migration_markdown: Option<String>,
target_display_name: String,
target_description: Option<String>,
can_opt_out: bool,
) -> ModelMigrationCopy {
if let Some(migration_markdown) = migration_markdown {
return ModelMigrationCopy {
heading: Vec::new(),
content: Vec::new(),
can_opt_out,
markdown: Some(fill_migration_markdown(
&migration_markdown,
current_model,
target_model,
)),
};
}
let heading_text = Span::from(format!(
"Codex just got an upgrade. Introducing {target_display_name}."
))
@@ -113,6 +130,7 @@ pub(crate) fn migration_copy_for_models(
heading: vec![heading_text],
content,
can_opt_out,
markdown: None,
}
}
@@ -237,9 +255,13 @@ impl WidgetRef for &ModelMigrationScreen {
let mut column = ColumnRenderable::new();
column.push("");
column.push(self.heading_line());
column.push(Line::from(""));
self.render_content(&mut column);
if let Some(markdown) = self.copy.markdown.as_ref() {
self.render_markdown_content(markdown, area.width, &mut column);
} else {
column.push(self.heading_line());
column.push(Line::from(""));
self.render_content(&mut column);
}
if self.copy.can_opt_out {
self.render_menu(&mut column);
}
@@ -290,6 +312,21 @@ impl ModelMigrationScreen {
}
}
fn render_markdown_content(
&self,
markdown: &str,
area_width: u16,
column: &mut ColumnRenderable,
) {
let horizontal_inset = 2;
let content_width = area_width.saturating_sub(horizontal_inset);
let wrap_width = (content_width > 0).then_some(content_width as usize);
let rendered = render_markdown_text_with_width(markdown, wrap_width);
for line in rendered.lines {
column.push(line.inset(Insets::tlbr(0, horizontal_inset, 0, 0)));
}
}
fn render_menu(&self, column: &mut ColumnRenderable) {
column.push(Line::from(""));
column.push(
@@ -348,6 +385,12 @@ fn is_ctrl_exit_combo(key_event: KeyEvent) -> bool {
&& matches!(key_event.code, KeyCode::Char('c') | KeyCode::Char('d'))
}
fn fill_migration_markdown(template: &str, current_model: &str, target_model: &str) -> String {
template
.replace("{model_from}", current_model)
.replace("{model_to}", target_model)
}
#[cfg(test)]
mod tests {
use super::ModelMigrationScreen;
@@ -378,6 +421,7 @@ mod tests {
"Upgrade to gpt-5.2-codex for the latest and greatest agentic coding model."
.to_string(),
),
None,
"gpt-5.1-codex-max".to_string(),
Some("Codex-optimized flagship for deep and fast reasoning.".to_string()),
true,
@@ -406,6 +450,7 @@ mod tests {
"gpt-5.1",
Some("https://www.codex.com/models/gpt-5.1".to_string()),
None,
None,
"gpt-5.1".to_string(),
Some("Broad world knowledge with strong general reasoning.".to_string()),
false,
@@ -432,6 +477,7 @@ mod tests {
"gpt-5.1-codex-max",
Some("https://www.codex.com/models/gpt-5.1-codex-max".to_string()),
None,
None,
"gpt-5.1-codex-max".to_string(),
Some("Codex-optimized flagship for deep and fast reasoning.".to_string()),
false,
@@ -458,6 +504,7 @@ mod tests {
"gpt-5.1-codex-mini",
Some("https://www.codex.com/models/gpt-5.1-codex-mini".to_string()),
None,
None,
"gpt-5.1-codex-mini".to_string(),
Some("Optimized for codex. Cheaper, faster, but less capable.".to_string()),
false,
@@ -480,6 +527,7 @@ mod tests {
"gpt-new",
Some("https://www.codex.com/models/gpt-new".to_string()),
None,
None,
"gpt-new".to_string(),
Some("Latest recommended model for better performance.".to_string()),
true,
@@ -508,6 +556,7 @@ mod tests {
"gpt-new",
Some("https://www.codex.com/models/gpt-new".to_string()),
None,
None,
"gpt-new".to_string(),
Some("Latest recommended model for better performance.".to_string()),
true,
@@ -1,9 +1,8 @@
---
source: tui/src/app.rs
assertion_line: 1579
expression: model_migration_copy_to_plain_text(&copy)
---
Codex just got an upgrade. Introducing gpt-5.2-codex.
**Codex just got an upgrade. Introducing gpt-5.2-codex.**
Codex is now powered by gpt-5.2-codex, our latest frontier agentic coding model. It is smarter and faster than its predecessors and capable of long-running project-scale work. Learn more about gpt-5.2-codex at https://openai.com/index/introducing-gpt-5-2-codex