mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
feat(model): add gpt-5-codex-mini presets
This commit is contained in:
@@ -38,6 +38,20 @@ const PRESETS: &[ModelPreset] = &[
|
|||||||
model: "gpt-5-codex",
|
model: "gpt-5-codex",
|
||||||
effort: Some(ReasoningEffort::High),
|
effort: Some(ReasoningEffort::High),
|
||||||
},
|
},
|
||||||
|
ModelPreset {
|
||||||
|
id: "gpt-5-codex-mini",
|
||||||
|
label: "gpt-5-codex-mini",
|
||||||
|
description: "Optimized for codex. Cheaper, faster, and less capable.",
|
||||||
|
model: "gpt-5-codex-mini",
|
||||||
|
effort: Some(ReasoningEffort::Medium),
|
||||||
|
},
|
||||||
|
ModelPreset {
|
||||||
|
id: "gpt-5-codex-mini-high",
|
||||||
|
label: "gpt-5-codex-mini high",
|
||||||
|
description: "Maximizes reasoning depth for complex or ambiguous problems",
|
||||||
|
model: "gpt-5-codex-mini",
|
||||||
|
effort: Some(ReasoningEffort::High),
|
||||||
|
},
|
||||||
ModelPreset {
|
ModelPreset {
|
||||||
id: "gpt-5-minimal",
|
id: "gpt-5-minimal",
|
||||||
label: "gpt-5 minimal",
|
label: "gpt-5 minimal",
|
||||||
@@ -68,6 +82,33 @@ const PRESETS: &[ModelPreset] = &[
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn builtin_model_presets(_auth_mode: Option<AuthMode>) -> Vec<ModelPreset> {
|
pub fn builtin_model_presets(auth_mode: Option<AuthMode>) -> Vec<ModelPreset> {
|
||||||
PRESETS.to_vec()
|
let allow_codex_mini = matches!(auth_mode, Some(AuthMode::ChatGPT));
|
||||||
|
PRESETS
|
||||||
|
.iter()
|
||||||
|
.filter(|preset| {
|
||||||
|
allow_codex_mini || preset.model != "gpt-5-codex-mini"
|
||||||
|
})
|
||||||
|
.copied()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chatgpt_accounts_include_codex_mini() {
|
||||||
|
let presets = builtin_model_presets(Some(AuthMode::ChatGPT));
|
||||||
|
assert!(presets.iter().filter(|preset| preset.model == "gpt-5-codex-mini").count() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn api_key_accounts_exclude_codex_mini() {
|
||||||
|
let presets = builtin_model_presets(Some(AuthMode::ApiKey));
|
||||||
|
assert!(!presets.iter().any(|preset| preset.model == "gpt-5-codex-mini"));
|
||||||
|
|
||||||
|
let presets = builtin_model_presets(None);
|
||||||
|
assert!(!presets.iter().any(|preset| preset.model == "gpt-5-codex-mini"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,10 +169,12 @@ impl ModelSelectionView {
|
|||||||
|
|
||||||
if is_new_model {
|
if is_new_model {
|
||||||
if previous_model.is_some() {
|
if previous_model.is_some() {
|
||||||
// Spacer plus header when switching between model groups.
|
// Spacer between model groups.
|
||||||
lines = lines.saturating_add(2);
|
lines = lines.saturating_add(1);
|
||||||
} else {
|
}
|
||||||
// Only the header for the first model group; initial spacer already counted.
|
// Header when entering a new model group.
|
||||||
|
lines = lines.saturating_add(1);
|
||||||
|
if Self::model_description(preset.model).is_some() {
|
||||||
lines = lines.saturating_add(1);
|
lines = lines.saturating_add(1);
|
||||||
}
|
}
|
||||||
previous_model = Some(preset.model);
|
previous_model = Some(preset.model);
|
||||||
@@ -218,10 +220,24 @@ impl ModelSelectionView {
|
|||||||
fn model_rank(model: &str) -> u8 {
|
fn model_rank(model: &str) -> u8 {
|
||||||
if model.eq_ignore_ascii_case("gpt-5-codex") {
|
if model.eq_ignore_ascii_case("gpt-5-codex") {
|
||||||
0
|
0
|
||||||
} else if model.eq_ignore_ascii_case("gpt-5") {
|
} else if model.eq_ignore_ascii_case("gpt-5-codex-mini") {
|
||||||
1
|
1
|
||||||
} else {
|
} else if model.eq_ignore_ascii_case("gpt-5") {
|
||||||
2
|
2
|
||||||
|
} else {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn model_description(model: &str) -> Option<&'static str> {
|
||||||
|
if model.eq_ignore_ascii_case("gpt-5-codex") {
|
||||||
|
Some("Optimized for coding.")
|
||||||
|
} else if model.eq_ignore_ascii_case("gpt-5-codex-mini") {
|
||||||
|
Some("Optimized for coding. Cheaper, faster, but less capable.")
|
||||||
|
} else if model.eq_ignore_ascii_case("gpt-5") {
|
||||||
|
Some("Broad world knowledge with strong general reasoning.")
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,6 +366,12 @@ impl ModelSelectionView {
|
|||||||
.fg(crate::colors::text_bright())
|
.fg(crate::colors::text_bright())
|
||||||
.add_modifier(Modifier::BOLD),
|
.add_modifier(Modifier::BOLD),
|
||||||
)]));
|
)]));
|
||||||
|
if let Some(desc) = Self::model_description(&preset.model) {
|
||||||
|
lines.push(Line::from(vec![Span::styled(
|
||||||
|
desc,
|
||||||
|
Style::default().fg(crate::colors::text_dim()),
|
||||||
|
)]));
|
||||||
|
}
|
||||||
previous_model = Some(preset.model);
|
previous_model = Some(preset.model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5515,16 +5515,33 @@ impl ChatWidget<'_> {
|
|||||||
|
|
||||||
/// Format model name with proper capitalization (e.g., "gpt-4" -> "GPT-4")
|
/// Format model name with proper capitalization (e.g., "gpt-4" -> "GPT-4")
|
||||||
fn format_model_name(&self, model_name: &str) -> String {
|
fn format_model_name(&self, model_name: &str) -> String {
|
||||||
|
fn format_segment(segment: &str) -> String {
|
||||||
|
if segment.eq_ignore_ascii_case("codex") {
|
||||||
|
return "Codex".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut chars = segment.chars();
|
||||||
|
match chars.next() {
|
||||||
|
Some(first) if first.is_ascii_alphabetic() => {
|
||||||
|
let mut formatted = String::new();
|
||||||
|
formatted.push(first.to_ascii_uppercase());
|
||||||
|
formatted.push_str(chars.as_str());
|
||||||
|
formatted
|
||||||
|
}
|
||||||
|
Some(first) => {
|
||||||
|
let mut formatted = String::new();
|
||||||
|
formatted.push(first);
|
||||||
|
formatted.push_str(chars.as_str());
|
||||||
|
formatted
|
||||||
|
}
|
||||||
|
None => String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(rest) = model_name.strip_prefix("gpt-") {
|
if let Some(rest) = model_name.strip_prefix("gpt-") {
|
||||||
let formatted_rest = rest
|
let formatted_rest = rest
|
||||||
.split('-')
|
.split('-')
|
||||||
.map(|segment| {
|
.map(format_segment)
|
||||||
if segment.eq_ignore_ascii_case("codex") {
|
|
||||||
"Codex".to_string()
|
|
||||||
} else {
|
|
||||||
segment.to_string()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("-");
|
.join("-");
|
||||||
format!("GPT-{}", formatted_rest)
|
format!("GPT-{}", formatted_rest)
|
||||||
@@ -23661,6 +23678,13 @@ mod tests {
|
|||||||
TaskCompleteEvent,
|
TaskCompleteEvent,
|
||||||
};
|
};
|
||||||
use code_core::protocol::AgentInfo as CoreAgentInfo;
|
use code_core::protocol::AgentInfo as CoreAgentInfo;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_model_name_capitalizes_codex_mini() {
|
||||||
|
let mut harness = ChatWidgetHarness::new();
|
||||||
|
let formatted = harness.chat().format_model_name("gpt-5-codex-mini");
|
||||||
|
assert_eq!(formatted, "GPT-5-Codex-Mini");
|
||||||
|
}
|
||||||
use ratatui::backend::TestBackend;
|
use ratatui::backend::TestBackend;
|
||||||
use ratatui::text::Line;
|
use ratatui::text::Line;
|
||||||
use ratatui::Terminal;
|
use ratatui::Terminal;
|
||||||
|
|||||||
Reference in New Issue
Block a user