mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
chore: rm hardcoded PRESETS list (#12650)
rm `PRESETS` list harcoded in `model_presets` as we now have bundled `models.json` with equivalent info. update logic to rely on bundled models instead, update tests.
This commit is contained in:
@@ -665,7 +665,7 @@ pub(crate) fn deserialize_config_toml_with_base(
|
||||
|
||||
fn load_catalog_json(path: &AbsolutePathBuf) -> std::io::Result<ModelsResponse> {
|
||||
let file_contents = std::fs::read_to_string(path)?;
|
||||
serde_json::from_str::<ModelsResponse>(&file_contents).map_err(|err| {
|
||||
let catalog = serde_json::from_str::<ModelsResponse>(&file_contents).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
format!(
|
||||
@@ -673,7 +673,17 @@ fn load_catalog_json(path: &AbsolutePathBuf) -> std::io::Result<ModelsResponse>
|
||||
path.display()
|
||||
),
|
||||
)
|
||||
})
|
||||
})?;
|
||||
if catalog.models.is_empty() {
|
||||
return Err(std::io::Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
format!(
|
||||
"model_catalog_json path `{}` must contain at least one model",
|
||||
path.display()
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(catalog)
|
||||
}
|
||||
|
||||
fn load_model_catalog(
|
||||
@@ -4466,6 +4476,32 @@ config_file = "./agents/researcher.toml"
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_catalog_json_rejects_empty_catalog() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let catalog_path = codex_home.path().join("catalog.json");
|
||||
std::fs::write(&catalog_path, r#"{"models":[]}"#)?;
|
||||
|
||||
let cfg = ConfigToml {
|
||||
model_catalog_json: Some(AbsolutePathBuf::from_absolute_path(catalog_path)?),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let err = Config::load_from_base_config_with_overrides(
|
||||
cfg,
|
||||
ConfigOverrides::default(),
|
||||
codex_home.path().to_path_buf(),
|
||||
)
|
||||
.expect_err("empty custom catalog should fail config load");
|
||||
|
||||
assert_eq!(err.kind(), ErrorKind::InvalidData);
|
||||
assert!(
|
||||
err.to_string().contains("must contain at least one model"),
|
||||
"unexpected error: {err}"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_test_fixture() -> std::io::Result<PrecedenceTestFixture> {
|
||||
let toml = r#"
|
||||
model = "o3"
|
||||
|
||||
@@ -10,7 +10,6 @@ use crate::error::Result as CoreResult;
|
||||
use crate::model_provider_info::ModelProviderInfo;
|
||||
use crate::models_manager::collaboration_mode_presets::builtin_collaboration_mode_presets;
|
||||
use crate::models_manager::model_info;
|
||||
use crate::models_manager::model_presets::builtin_model_presets;
|
||||
use codex_api::ModelsClient;
|
||||
use codex_api::ReqwestTransport;
|
||||
use codex_protocol::config_types::CollaborationModeMask;
|
||||
@@ -45,7 +44,6 @@ pub enum RefreshStrategy {
|
||||
/// Coordinates remote model discovery plus cached metadata on disk.
|
||||
#[derive(Debug)]
|
||||
pub struct ModelsManager {
|
||||
local_models: Vec<ModelPreset>,
|
||||
remote_models: RwLock<Vec<ModelInfo>>,
|
||||
has_custom_model_catalog: bool,
|
||||
auth_manager: Arc<AuthManager>,
|
||||
@@ -57,7 +55,7 @@ pub struct ModelsManager {
|
||||
impl ModelsManager {
|
||||
/// Construct a manager scoped to the provided `AuthManager`.
|
||||
///
|
||||
/// Uses `codex_home` to store cached model metadata and initializes with built-in presets.
|
||||
/// Uses `codex_home` to store cached model metadata and initializes with bundled catalog
|
||||
/// When `model_catalog` is provided, it becomes the authoritative remote model list and
|
||||
/// background refreshes from `/models` are disabled.
|
||||
pub fn new(
|
||||
@@ -70,9 +68,11 @@ impl ModelsManager {
|
||||
let has_custom_model_catalog = model_catalog.is_some();
|
||||
let remote_models = model_catalog
|
||||
.map(|catalog| catalog.models)
|
||||
.unwrap_or_else(|| Self::load_remote_models_from_file().unwrap_or_default());
|
||||
.unwrap_or_else(|| {
|
||||
Self::load_remote_models_from_file()
|
||||
.unwrap_or_else(|err| panic!("failed to load bundled models.json: {err}"))
|
||||
});
|
||||
Self {
|
||||
local_models: builtin_model_presets(auth_manager.auth_mode()),
|
||||
remote_models: RwLock::new(remote_models),
|
||||
has_custom_model_catalog,
|
||||
auth_manager,
|
||||
@@ -309,29 +309,17 @@ impl ModelsManager {
|
||||
true
|
||||
}
|
||||
|
||||
/// Merge remote model metadata into picker-ready presets, preserving existing entries.
|
||||
/// Build picker-ready presets from the active catalog snapshot.
|
||||
fn build_available_models(&self, mut remote_models: Vec<ModelInfo>) -> Vec<ModelPreset> {
|
||||
remote_models.sort_by(|a, b| a.priority.cmp(&b.priority));
|
||||
|
||||
let remote_presets: Vec<ModelPreset> = remote_models.into_iter().map(Into::into).collect();
|
||||
let existing_presets = self.local_models.clone();
|
||||
let mut merged_presets = ModelPreset::merge(remote_presets, existing_presets);
|
||||
let mut presets: Vec<ModelPreset> = remote_models.into_iter().map(Into::into).collect();
|
||||
let chatgpt_mode = matches!(self.auth_manager.auth_mode(), Some(AuthMode::Chatgpt));
|
||||
merged_presets = ModelPreset::filter_by_auth(merged_presets, chatgpt_mode);
|
||||
presets = ModelPreset::filter_by_auth(presets, chatgpt_mode);
|
||||
|
||||
for preset in &mut merged_presets {
|
||||
preset.is_default = false;
|
||||
}
|
||||
if let Some(default) = merged_presets
|
||||
.iter_mut()
|
||||
.find(|preset| preset.show_in_picker)
|
||||
{
|
||||
default.is_default = true;
|
||||
} else if let Some(default) = merged_presets.first_mut() {
|
||||
default.is_default = true;
|
||||
}
|
||||
ModelPreset::mark_default_by_picker_visibility(&mut presets);
|
||||
|
||||
merged_presets
|
||||
presets
|
||||
}
|
||||
|
||||
async fn get_remote_models(&self) -> Vec<ModelInfo> {
|
||||
@@ -351,8 +339,10 @@ impl ModelsManager {
|
||||
let cache_path = codex_home.join(MODEL_CACHE_FILE);
|
||||
let cache_manager = ModelsCacheManager::new(cache_path, DEFAULT_MODEL_CACHE_TTL);
|
||||
Self {
|
||||
local_models: builtin_model_presets(auth_manager.auth_mode()),
|
||||
remote_models: RwLock::new(Self::load_remote_models_from_file().unwrap_or_default()),
|
||||
remote_models: RwLock::new(
|
||||
Self::load_remote_models_from_file()
|
||||
.unwrap_or_else(|err| panic!("failed to load bundled models.json: {err}")),
|
||||
),
|
||||
has_custom_model_catalog: false,
|
||||
auth_manager,
|
||||
etag: RwLock::new(None),
|
||||
@@ -366,7 +356,9 @@ impl ModelsManager {
|
||||
if let Some(model) = model {
|
||||
return model.to_string();
|
||||
}
|
||||
let presets = builtin_model_presets(None);
|
||||
let mut models = Self::load_remote_models_from_file().unwrap_or_default();
|
||||
models.sort_by(|a, b| a.priority.cmp(&b.priority));
|
||||
let presets: Vec<ModelPreset> = models.into_iter().map(Into::into).collect();
|
||||
presets
|
||||
.iter()
|
||||
.find(|preset| preset.show_in_picker)
|
||||
@@ -862,12 +854,11 @@ mod tests {
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::from_api_key("Test API Key"));
|
||||
let provider = provider_for("http://example.test".to_string());
|
||||
let mut manager = ModelsManager::with_provider_for_tests(
|
||||
let manager = ModelsManager::with_provider_for_tests(
|
||||
codex_home.path().to_path_buf(),
|
||||
auth_manager,
|
||||
provider,
|
||||
);
|
||||
manager.local_models = Vec::new();
|
||||
|
||||
let hidden_model = remote_model_with_visibility("hidden", "Hidden", 0, "hide");
|
||||
let visible_model = remote_model_with_visibility("visible", "Visible", 1, "list");
|
||||
|
||||
@@ -1,371 +1,6 @@
|
||||
use crate::auth::AuthMode;
|
||||
use codex_protocol::openai_models::ModelPreset;
|
||||
use codex_protocol::openai_models::ModelUpgrade;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::openai_models::ReasoningEffortPreset;
|
||||
use codex_protocol::openai_models::default_input_modalities;
|
||||
use indoc::indoc;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
/// Legacy notice keys kept for config compatibility with older migration prompts.
|
||||
///
|
||||
/// Hardcoded model presets were removed; model listings are now derived from the active catalog.
|
||||
pub const HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG: &str = "hide_gpt5_1_migration_prompt";
|
||||
pub const HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG: &str =
|
||||
"hide_gpt-5.1-codex-max_migration_prompt";
|
||||
|
||||
pub(crate) static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
|
||||
vec![
|
||||
ModelPreset {
|
||||
id: "gpt-5.2-codex".to_string(),
|
||||
model: "gpt-5.2-codex".to_string(),
|
||||
display_name: "gpt-5.2-codex".to_string(),
|
||||
description: "Latest frontier agentic coding model.".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Fast responses with lighter reasoning".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Balances speed and reasoning depth for everyday tasks".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Greater reasoning depth for complex problems".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::XHigh,
|
||||
description: "Extra high reasoning depth for complex problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: true,
|
||||
is_default: true,
|
||||
upgrade: None,
|
||||
show_in_picker: true,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "gpt-5.1-codex-max".to_string(),
|
||||
model: "gpt-5.1-codex-max".to_string(),
|
||||
display_name: "gpt-5.1-codex-max".to_string(),
|
||||
description: "Codex-optimized flagship for deep and fast reasoning.".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Fast responses with lighter reasoning".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Balances speed and reasoning depth for everyday tasks".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Greater reasoning depth for complex problems".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::XHigh,
|
||||
description: "Extra high reasoning depth for complex problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_52_codex_upgrade()),
|
||||
show_in_picker: true,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "gpt-5.1-codex-mini".to_string(),
|
||||
model: "gpt-5.1-codex-mini".to_string(),
|
||||
display_name: "gpt-5.1-codex-mini".to_string(),
|
||||
description: "Optimized for codex. Cheaper, faster, but less capable.".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Dynamically adjusts reasoning based on the task".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Maximizes reasoning depth for complex or ambiguous problems"
|
||||
.to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_52_codex_upgrade()),
|
||||
show_in_picker: true,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "gpt-5.2".to_string(),
|
||||
model: "gpt-5.2".to_string(),
|
||||
display_name: "gpt-5.2".to_string(),
|
||||
description: "Latest frontier model with improvements across knowledge, reasoning and coding".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Balances speed with some reasoning; useful for straightforward queries and short explanations".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Provides a solid balance of reasoning depth and latency for general-purpose tasks".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Maximizes reasoning depth for complex or ambiguous problems".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::XHigh,
|
||||
description: "Extra high reasoning depth for complex problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_52_codex_upgrade()),
|
||||
show_in_picker: true,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "bengalfox".to_string(),
|
||||
model: "bengalfox".to_string(),
|
||||
display_name: "bengalfox".to_string(),
|
||||
description: "bengalfox".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Fast responses with lighter reasoning".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Balances speed and reasoning depth for everyday tasks".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Greater reasoning depth for complex problems".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::XHigh,
|
||||
description: "Extra high reasoning depth for complex problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: true,
|
||||
is_default: false,
|
||||
upgrade: None,
|
||||
show_in_picker: false,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "boomslang".to_string(),
|
||||
model: "boomslang".to_string(),
|
||||
display_name: "boomslang".to_string(),
|
||||
description: "boomslang".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Balances speed with some reasoning; useful for straightforward queries and short explanations".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Provides a solid balance of reasoning depth and latency for general-purpose tasks".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Maximizes reasoning depth for complex or ambiguous problems".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::XHigh,
|
||||
description: "Extra high reasoning depth for complex problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: None,
|
||||
show_in_picker: false,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
// Deprecated models.
|
||||
ModelPreset {
|
||||
id: "gpt-5-codex".to_string(),
|
||||
model: "gpt-5-codex".to_string(),
|
||||
display_name: "gpt-5-codex".to_string(),
|
||||
description: "Optimized for codex.".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Fastest responses with limited reasoning".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Dynamically adjusts reasoning based on the task".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Maximizes reasoning depth for complex or ambiguous problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_52_codex_upgrade()),
|
||||
show_in_picker: false,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "gpt-5-codex-mini".to_string(),
|
||||
model: "gpt-5-codex-mini".to_string(),
|
||||
display_name: "gpt-5-codex-mini".to_string(),
|
||||
description: "Optimized for codex. Cheaper, faster, but less capable.".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Dynamically adjusts reasoning based on the task".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Maximizes reasoning depth for complex or ambiguous problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_52_codex_upgrade()),
|
||||
show_in_picker: false,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "gpt-5.1-codex".to_string(),
|
||||
model: "gpt-5.1-codex".to_string(),
|
||||
display_name: "gpt-5.1-codex".to_string(),
|
||||
description: "Optimized for codex.".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Fastest responses with limited reasoning".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Dynamically adjusts reasoning based on the task".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Maximizes reasoning depth for complex or ambiguous problems"
|
||||
.to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_52_codex_upgrade()),
|
||||
show_in_picker: false,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "gpt-5".to_string(),
|
||||
model: "gpt-5".to_string(),
|
||||
display_name: "gpt-5".to_string(),
|
||||
description: "Broad world knowledge with strong general reasoning.".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Minimal,
|
||||
description: "Fastest responses with little reasoning".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Balances speed with some reasoning; useful for straightforward queries and short explanations".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Provides a solid balance of reasoning depth and latency for general-purpose tasks".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Maximizes reasoning depth for complex or ambiguous problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_52_codex_upgrade()),
|
||||
show_in_picker: false,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
ModelPreset {
|
||||
id: "gpt-5.1".to_string(),
|
||||
model: "gpt-5.1".to_string(),
|
||||
display_name: "gpt-5.1".to_string(),
|
||||
description: "Broad world knowledge with strong general reasoning.".to_string(),
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Low,
|
||||
description: "Balances speed with some reasoning; useful for straightforward queries and short explanations".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "Provides a solid balance of reasoning depth and latency for general-purpose tasks".to_string(),
|
||||
},
|
||||
ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::High,
|
||||
description: "Maximizes reasoning depth for complex or ambiguous problems".to_string(),
|
||||
},
|
||||
],
|
||||
supports_personality: false,
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_52_codex_upgrade()),
|
||||
show_in_picker: false,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
fn gpt_52_codex_upgrade() -> ModelUpgrade {
|
||||
ModelUpgrade {
|
||||
id: "gpt-5.2-codex".to_string(),
|
||||
reasoning_effort_mapping: None,
|
||||
migration_config_key: "gpt-5.2-codex".to_string(),
|
||||
model_link: Some("https://openai.com/index/introducing-gpt-5-2-codex".to_string()),
|
||||
upgrade_copy: Some(
|
||||
"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."
|
||||
.to_string(),
|
||||
),
|
||||
migration_markdown: Some(
|
||||
indoc! {r#"
|
||||
**Codex just got an upgrade. Introducing {model_to}.**
|
||||
|
||||
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 {model_to} at https://openai.com/index/introducing-gpt-5-2-codex
|
||||
|
||||
You can continue using {model_from} if you prefer.
|
||||
"#}
|
||||
.to_string(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn builtin_model_presets(_auth_mode: Option<AuthMode>) -> Vec<ModelPreset> {
|
||||
PRESETS.iter().cloned().collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn only_one_default_model_is_configured() {
|
||||
let default_models = PRESETS.iter().filter(|preset| preset.is_default).count();
|
||||
assert!(default_models == 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ use std::sync::Arc;
|
||||
use codex_protocol::config_types::CollaborationModeMask;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
use codex_protocol::openai_models::ModelPreset;
|
||||
use codex_protocol::openai_models::ModelsResponse;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::AuthManager;
|
||||
use crate::CodexAuth;
|
||||
@@ -18,10 +20,19 @@ use crate::ThreadManager;
|
||||
use crate::config::Config;
|
||||
use crate::models_manager::collaboration_mode_presets;
|
||||
use crate::models_manager::manager::ModelsManager;
|
||||
use crate::models_manager::model_presets;
|
||||
use crate::thread_manager;
|
||||
use crate::unified_exec;
|
||||
|
||||
static TEST_MODEL_PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
|
||||
let file_contents = include_str!("../models.json");
|
||||
let mut response: ModelsResponse = serde_json::from_str(file_contents)
|
||||
.unwrap_or_else(|err| panic!("bundled models.json should parse: {err}"));
|
||||
response.models.sort_by(|a, b| a.priority.cmp(&b.priority));
|
||||
let mut presets: Vec<ModelPreset> = response.models.into_iter().map(Into::into).collect();
|
||||
ModelPreset::mark_default_by_picker_visibility(&mut presets);
|
||||
presets
|
||||
});
|
||||
|
||||
pub fn set_thread_manager_test_mode(enabled: bool) {
|
||||
thread_manager::set_thread_manager_test_mode_for_tests(enabled);
|
||||
}
|
||||
@@ -70,7 +81,7 @@ pub fn construct_model_info_offline(model: &str, config: &Config) -> ModelInfo {
|
||||
}
|
||||
|
||||
pub fn all_model_presets() -> &'static Vec<ModelPreset> {
|
||||
&model_presets::PRESETS
|
||||
&TEST_MODEL_PRESETS
|
||||
}
|
||||
|
||||
pub fn builtin_collaboration_mode_presets() -> Vec<CollaborationModeMask> {
|
||||
|
||||
Reference in New Issue
Block a user