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
+6
View File
@@ -231,6 +231,7 @@ async fn handle_model_migration_prompt_if_needed(
id: target_model,
reasoning_effort_mapping,
migration_config_key,
migration_markdown,
..
}) = upgrade
{
@@ -273,6 +274,7 @@ async fn handle_model_migration_prompt_if_needed(
&target_model,
heading_label,
target_description,
migration_markdown.clone(),
can_opt_out,
);
match run_model_migration_prompt(tui, prompt_copy).await {
@@ -2384,6 +2386,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);
@@ -2478,6 +2483,7 @@ mod tests {
&upgrade.id,
target.display_name,
target_description,
upgrade.migration_markdown.clone(),
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,13 +57,28 @@ impl MigrationMenuOption {
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn migration_copy_for_models(
current_model: &str,
target_model: &str,
target_display_name: String,
target_description: Option<String>,
migration_markdown: 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!("Try {target_display_name}")).bold();
let description_line = target_description
.filter(|desc| !desc.is_empty())
@@ -93,6 +110,7 @@ pub(crate) fn migration_copy_for_models(
heading: vec![heading_text],
content,
can_opt_out,
markdown: None,
}
}
@@ -218,9 +236,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);
}
@@ -271,6 +293,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(
@@ -329,6 +366,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;
@@ -356,6 +399,7 @@ mod tests {
"gpt-5.1-codex-max",
"gpt-5.1-codex-max".to_string(),
Some("Codex-optimized flagship for deep and fast reasoning.".to_string()),
None,
true,
),
);
@@ -382,6 +426,7 @@ mod tests {
"gpt-5.1",
"gpt-5.1".to_string(),
Some("Broad world knowledge with strong general reasoning.".to_string()),
None,
false,
),
);
@@ -406,6 +451,7 @@ mod tests {
"gpt-5.1-codex-max",
"gpt-5.1-codex-max".to_string(),
Some("Codex-optimized flagship for deep and fast reasoning.".to_string()),
None,
false,
),
);
@@ -430,6 +476,7 @@ mod tests {
"gpt-5.1-codex-mini",
"gpt-5.1-codex-mini".to_string(),
Some("Optimized for codex. Cheaper, faster, but less capable.".to_string()),
None,
false,
),
);
@@ -450,6 +497,7 @@ mod tests {
"gpt-new",
"gpt-new".to_string(),
Some("Latest recommended model for better performance.".to_string()),
None,
true,
),
);
@@ -476,6 +524,7 @@ mod tests {
"gpt-new",
"gpt-new".to_string(),
Some("Latest recommended model for better performance.".to_string()),
None,
true,
),
);
@@ -1,12 +1,9 @@
---
source: tui2/src/app.rs
assertion_line: 2314
expression: model_migration_copy_to_plain_text(&copy)
---
Try gpt-5.2-codex
**Codex just got an upgrade. Introducing gpt-5.2-codex.**
We recommend switching from gpt-5.1-codex to gpt-5.2-codex.
Latest frontier agentic coding model.
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
You can continue using gpt-5.1-codex if you prefer.