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",
|
||||
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 {
|
||||
id: "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> {
|
||||
PRESETS.to_vec()
|
||||
pub fn builtin_model_presets(auth_mode: Option<AuthMode>) -> Vec<ModelPreset> {
|
||||
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 previous_model.is_some() {
|
||||
// Spacer plus header when switching between model groups.
|
||||
lines = lines.saturating_add(2);
|
||||
} else {
|
||||
// Only the header for the first model group; initial spacer already counted.
|
||||
// Spacer between model groups.
|
||||
lines = lines.saturating_add(1);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
previous_model = Some(preset.model);
|
||||
@@ -218,10 +220,24 @@ impl ModelSelectionView {
|
||||
fn model_rank(model: &str) -> u8 {
|
||||
if model.eq_ignore_ascii_case("gpt-5-codex") {
|
||||
0
|
||||
} else if model.eq_ignore_ascii_case("gpt-5") {
|
||||
} else if model.eq_ignore_ascii_case("gpt-5-codex-mini") {
|
||||
1
|
||||
} else {
|
||||
} else if model.eq_ignore_ascii_case("gpt-5") {
|
||||
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())
|
||||
.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);
|
||||
}
|
||||
|
||||
|
||||
@@ -5515,16 +5515,33 @@ impl ChatWidget<'_> {
|
||||
|
||||
/// Format model name with proper capitalization (e.g., "gpt-4" -> "GPT-4")
|
||||
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-") {
|
||||
let formatted_rest = rest
|
||||
.split('-')
|
||||
.map(|segment| {
|
||||
if segment.eq_ignore_ascii_case("codex") {
|
||||
"Codex".to_string()
|
||||
} else {
|
||||
segment.to_string()
|
||||
}
|
||||
})
|
||||
.map(format_segment)
|
||||
.collect::<Vec<_>>()
|
||||
.join("-");
|
||||
format!("GPT-{}", formatted_rest)
|
||||
@@ -23661,6 +23678,13 @@ mod tests {
|
||||
TaskCompleteEvent,
|
||||
};
|
||||
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::text::Line;
|
||||
use ratatui::Terminal;
|
||||
|
||||
Reference in New Issue
Block a user