Migrate model family to models manager (#7565)

This PR moves `ModelsFamily` to `openai_models`. It also propagates
`ModelsManager` to session services and use it to drive model family. We
also make `derive_default_model_family` private because it's a step
towards what we want: one place that gives model configuration.

This is a second step at having one source of truth for models
information and config: `ModelsManager`.

Next steps would be to remove `ModelsFamily` from config. That's massive
because it's being used in 41 occasions mostly pre launching `codex`.
Also, we need to make `find_family_for_model` private. It's also big
because it's being used in 21 occasions ~ all tests.
This commit is contained in:
Ahmed Ibrahim
2025-12-03 18:49:47 -08:00
committed by GitHub
Unverified
parent 8da91d1c89
commit cee37a32b2
20 changed files with 109 additions and 82 deletions
+1 -1
View File
@@ -46,10 +46,10 @@ use crate::default_client::build_reqwest_client;
use crate::error::CodexErr;
use crate::error::Result;
use crate::flags::CODEX_RS_SSE_FIXTURE;
use crate::model_family::ModelFamily;
use crate::model_provider_info::ModelProviderInfo;
use crate::model_provider_info::WireApi;
use crate::openai_model_info::get_model_info;
use crate::openai_models::model_family::ModelFamily;
use crate::tools::spec::create_tools_json_for_chat_completions_api;
use crate::tools::spec::create_tools_json_for_responses_api;
+3 -3
View File
@@ -1,6 +1,6 @@
use crate::client_common::tools::ToolSpec;
use crate::error::Result;
use crate::model_family::ModelFamily;
use crate::openai_models::model_family::ModelFamily;
pub use codex_api::common::ResponseEvent;
use codex_apply_patch::APPLY_PATCH_TOOL_INSTRUCTIONS;
use codex_protocol::models::ResponseItem;
@@ -252,7 +252,7 @@ impl Stream for ResponseStream {
#[cfg(test)]
mod tests {
use crate::model_family::find_family_for_model;
use crate::openai_models::model_family::find_family_for_model;
use codex_api::ResponsesApiRequest;
use codex_api::common::OpenAiVerbosity;
use codex_api::common::TextControls;
@@ -309,7 +309,7 @@ mod tests {
},
];
for test_case in test_cases {
let model_family = find_family_for_model(test_case.slug).expect("known model slug");
let model_family = find_family_for_model(test_case.slug);
let expected = if test_case.expects_apply_patch_instructions {
format!(
"{}\n{}",
+22 -12
View File
@@ -14,6 +14,7 @@ use crate::compact_remote::run_inline_remote_auto_compact_task;
use crate::features::Feature;
use crate::features::Features;
use crate::function_tool::FunctionCallError;
use crate::openai_models::models_manager::ModelsManager;
use crate::parse_command::parse_command;
use crate::parse_turn_item;
use crate::response_processing::process_items;
@@ -74,7 +75,6 @@ use crate::error::Result as CodexResult;
use crate::exec::StreamOutput;
use crate::mcp::auth::compute_auth_statuses;
use crate::mcp_connection_manager::McpConnectionManager;
use crate::model_family::find_family_for_model;
use crate::openai_model_info::get_model_info;
use crate::project_doc::get_user_instructions;
use crate::protocol::AgentMessageContentDeltaEvent;
@@ -163,6 +163,7 @@ impl Codex {
pub async fn spawn(
config: Config,
auth_manager: Arc<AuthManager>,
models_manager: Arc<ModelsManager>,
conversation_history: InitialHistory,
session_source: SessionSource,
) -> CodexResult<CodexSpawnOk> {
@@ -200,6 +201,7 @@ impl Codex {
session_configuration,
config.clone(),
auth_manager.clone(),
models_manager.clone(),
tx_event.clone(),
conversation_history,
session_source_clone,
@@ -394,6 +396,7 @@ pub(crate) struct SessionSettingsUpdate {
impl Session {
fn make_turn_context(
auth_manager: Option<Arc<AuthManager>>,
models_manager: &ModelsManager,
otel_event_manager: &OtelEventManager,
provider: ModelProviderInfo,
session_configuration: &SessionConfiguration,
@@ -402,8 +405,7 @@ impl Session {
) -> TurnContext {
let config = session_configuration.original_config_do_not_use.clone();
let features = &config.features;
let model_family = find_family_for_model(&session_configuration.model)
.unwrap_or_else(|| config.model_family.clone());
let model_family = models_manager.construct_model_family(&session_configuration.model);
let mut per_turn_config = (*config).clone();
per_turn_config.model = session_configuration.model.clone();
per_turn_config.model_family = model_family.clone();
@@ -459,6 +461,7 @@ impl Session {
session_configuration: SessionConfiguration,
config: Arc<Config>,
auth_manager: Arc<AuthManager>,
models_manager: Arc<ModelsManager>,
tx_event: Sender<Event>,
initial_history: InitialHistory,
session_source: SessionSource,
@@ -570,6 +573,7 @@ impl Session {
show_raw_agent_reasoning: config.show_raw_agent_reasoning,
auth_manager: Arc::clone(&auth_manager),
otel_event_manager,
models_manager: Arc::clone(&models_manager),
tool_approvals: Mutex::new(ApprovalStore::default()),
};
@@ -756,6 +760,7 @@ impl Session {
let mut turn_context: TurnContext = Self::make_turn_context(
Some(Arc::clone(&self.services.auth_manager)),
&self.services.models_manager,
&self.services.otel_event_manager,
session_configuration.provider.clone(),
&session_configuration,
@@ -1824,8 +1829,7 @@ async fn spawn_review_thread(
resolved: crate::review_prompts::ResolvedReviewRequest,
) {
let model = config.review_model.clone();
let review_model_family = find_family_for_model(&model)
.unwrap_or_else(|| parent_turn_context.client.get_model_family());
let review_model_family = sess.services.models_manager.construct_model_family(&model);
// For reviews, disable web_search and view_image regardless of global settings.
let mut review_features = sess.features.clone();
review_features
@@ -2083,13 +2087,13 @@ async fn run_turn(
let mut base_instructions = turn_context.base_instructions.clone();
if parallel_tool_calls {
static INSTRUCTIONS: &str = include_str!("../templates/parallel/instructions.md");
if let Some(family) =
find_family_for_model(&sess.state.lock().await.session_configuration.model)
{
let mut new_instructions = base_instructions.unwrap_or(family.base_instructions);
new_instructions.push_str(INSTRUCTIONS);
base_instructions = Some(new_instructions);
}
let family = sess
.services
.models_manager
.construct_model_family(&sess.state.lock().await.session_configuration.model);
let mut new_instructions = base_instructions.unwrap_or(family.base_instructions);
new_instructions.push_str(INSTRUCTIONS);
base_instructions = Some(new_instructions);
}
let prompt = Prompt {
input,
@@ -2751,6 +2755,7 @@ mod tests {
false,
config.cli_auth_credentials_store_mode,
);
let models_manager = Arc::new(ModelsManager::new(auth_manager.get_auth_mode()));
let session_configuration = SessionConfiguration {
provider: config.model_provider.clone(),
@@ -2781,11 +2786,13 @@ mod tests {
show_raw_agent_reasoning: config.show_raw_agent_reasoning,
auth_manager: Arc::clone(&auth_manager),
otel_event_manager: otel_event_manager.clone(),
models_manager: models_manager.clone(),
tool_approvals: Mutex::new(ApprovalStore::default()),
};
let turn_context = Session::make_turn_context(
Some(Arc::clone(&auth_manager)),
&models_manager,
&otel_event_manager,
session_configuration.provider.clone(),
&session_configuration,
@@ -2829,6 +2836,7 @@ mod tests {
false,
config.cli_auth_credentials_store_mode,
);
let models_manager = Arc::new(ModelsManager::new(auth_manager.get_auth_mode()));
let session_configuration = SessionConfiguration {
provider: config.model_provider.clone(),
@@ -2859,11 +2867,13 @@ mod tests {
show_raw_agent_reasoning: config.show_raw_agent_reasoning,
auth_manager: Arc::clone(&auth_manager),
otel_event_manager: otel_event_manager.clone(),
models_manager: models_manager.clone(),
tool_approvals: Mutex::new(ApprovalStore::default()),
};
let turn_context = Arc::new(Session::make_turn_context(
Some(Arc::clone(&auth_manager)),
&models_manager,
&otel_event_manager,
session_configuration.provider.clone(),
&session_configuration,
+6
View File
@@ -25,6 +25,7 @@ use crate::codex::Session;
use crate::codex::TurnContext;
use crate::config::Config;
use crate::error::CodexErr;
use crate::openai_models::models_manager::ModelsManager;
use codex_protocol::protocol::InitialHistory;
/// Start an interactive sub-Codex conversation and return IO channels.
@@ -35,6 +36,7 @@ use codex_protocol::protocol::InitialHistory;
pub(crate) async fn run_codex_conversation_interactive(
config: Config,
auth_manager: Arc<AuthManager>,
models_manager: Arc<ModelsManager>,
parent_session: Arc<Session>,
parent_ctx: Arc<TurnContext>,
cancel_token: CancellationToken,
@@ -46,6 +48,7 @@ pub(crate) async fn run_codex_conversation_interactive(
let CodexSpawnOk { codex, .. } = Codex::spawn(
config,
auth_manager,
models_manager,
initial_history.unwrap_or(InitialHistory::New),
SessionSource::SubAgent(SubAgentSource::Review),
)
@@ -88,9 +91,11 @@ pub(crate) async fn run_codex_conversation_interactive(
/// Convenience wrapper for one-time use with an initial prompt.
///
/// Internally calls the interactive variant, then immediately submits the provided input.
#[allow(clippy::too_many_arguments)]
pub(crate) async fn run_codex_conversation_one_shot(
config: Config,
auth_manager: Arc<AuthManager>,
models_manager: Arc<ModelsManager>,
input: Vec<UserInput>,
parent_session: Arc<Session>,
parent_ctx: Arc<TurnContext>,
@@ -103,6 +108,7 @@ pub(crate) async fn run_codex_conversation_one_shot(
let io = run_codex_conversation_interactive(
config,
auth_manager,
models_manager,
parent_session,
parent_ctx,
child_cancel.clone(),
+8 -9
View File
@@ -22,14 +22,13 @@ use crate::features::FeatureOverrides;
use crate::features::Features;
use crate::features::FeaturesToml;
use crate::git_info::resolve_root_git_project_for_trust;
use crate::model_family::ModelFamily;
use crate::model_family::derive_default_model_family;
use crate::model_family::find_family_for_model;
use crate::model_provider_info::LMSTUDIO_OSS_PROVIDER_ID;
use crate::model_provider_info::ModelProviderInfo;
use crate::model_provider_info::OLLAMA_OSS_PROVIDER_ID;
use crate::model_provider_info::built_in_model_providers;
use crate::openai_model_info::get_model_info;
use crate::openai_models::model_family::ModelFamily;
use crate::openai_models::model_family::find_family_for_model;
use crate::project_doc::DEFAULT_PROJECT_DOC_FILENAME;
use crate::project_doc::LOCAL_PROJECT_DOC_FILENAME;
use crate::protocol::AskForApproval;
@@ -82,6 +81,7 @@ pub struct Config {
/// Model used specifically for review sessions. Defaults to "gpt-5.1-codex-max".
pub review_model: String,
// todo(aibrahim): remove this field
pub model_family: ModelFamily,
/// Size of the context window for the model, in tokens.
@@ -1109,8 +1109,7 @@ impl Config {
.or(cfg.model)
.unwrap_or_else(default_model);
let mut model_family =
find_family_for_model(&model).unwrap_or_else(|| derive_default_model_family(&model));
let mut model_family = find_family_for_model(&model);
if let Some(supports_reasoning_summaries) = cfg.model_supports_reasoning_summaries {
model_family.supports_reasoning_summaries = supports_reasoning_summaries;
@@ -2955,7 +2954,7 @@ model_verbosity = "high"
Config {
model: "o3".to_string(),
review_model: OPENAI_DEFAULT_REVIEW_MODEL.to_string(),
model_family: find_family_for_model("o3").expect("known model slug"),
model_family: find_family_for_model("o3"),
model_context_window: Some(200_000),
model_auto_compact_token_limit: Some(180_000),
model_provider_id: "openai".to_string(),
@@ -3029,7 +3028,7 @@ model_verbosity = "high"
let expected_gpt3_profile_config = Config {
model: "gpt-3.5-turbo".to_string(),
review_model: OPENAI_DEFAULT_REVIEW_MODEL.to_string(),
model_family: find_family_for_model("gpt-3.5-turbo").expect("known model slug"),
model_family: find_family_for_model("gpt-3.5-turbo"),
model_context_window: Some(16_385),
model_auto_compact_token_limit: Some(14_746),
model_provider_id: "openai-chat-completions".to_string(),
@@ -3118,7 +3117,7 @@ model_verbosity = "high"
let expected_zdr_profile_config = Config {
model: "o3".to_string(),
review_model: OPENAI_DEFAULT_REVIEW_MODEL.to_string(),
model_family: find_family_for_model("o3").expect("known model slug"),
model_family: find_family_for_model("o3"),
model_context_window: Some(200_000),
model_auto_compact_token_limit: Some(180_000),
model_provider_id: "openai".to_string(),
@@ -3193,7 +3192,7 @@ model_verbosity = "high"
let expected_gpt5_profile_config = Config {
model: "gpt-5.1".to_string(),
review_model: OPENAI_DEFAULT_REVIEW_MODEL.to_string(),
model_family: find_family_for_model("gpt-5.1").expect("known model slug"),
model_family: find_family_for_model("gpt-5.1"),
model_context_window: Some(272_000),
model_auto_compact_token_limit: Some(244_800),
model_provider_id: "openai".to_string(),
+17 -3
View File
@@ -65,14 +65,19 @@ impl ConversationManager {
}
pub async fn new_conversation(&self, config: Config) -> CodexResult<NewConversation> {
self.spawn_conversation(config, self.auth_manager.clone())
.await
self.spawn_conversation(
config,
self.auth_manager.clone(),
self.models_manager.clone(),
)
.await
}
async fn spawn_conversation(
&self,
config: Config,
auth_manager: Arc<AuthManager>,
models_manager: Arc<ModelsManager>,
) -> CodexResult<NewConversation> {
let CodexSpawnOk {
codex,
@@ -80,6 +85,7 @@ impl ConversationManager {
} = Codex::spawn(
config,
auth_manager,
models_manager,
InitialHistory::New,
self.session_source.clone(),
)
@@ -156,6 +162,7 @@ impl ConversationManager {
} = Codex::spawn(
config,
auth_manager,
self.models_manager.clone(),
initial_history,
self.session_source.clone(),
)
@@ -193,7 +200,14 @@ impl ConversationManager {
let CodexSpawnOk {
codex,
conversation_id,
} = Codex::spawn(config, auth_manager, history, self.session_source.clone()).await?;
} = Codex::spawn(
config,
auth_manager,
self.models_manager.clone(),
history,
self.session_source.clone(),
)
.await?;
self.finalize_spawn(codex, conversation_id).await
}
-1
View File
@@ -67,7 +67,6 @@ pub use conversation_manager::NewConversation;
pub use auth::AuthManager;
pub use auth::CodexAuth;
pub mod default_client;
pub mod model_family;
mod openai_model_info;
pub mod project_doc;
mod rollout;
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::model_family::ModelFamily;
use crate::openai_models::model_family::ModelFamily;
// Shared constants for commonly used window/token sizes.
pub(crate) const CONTEXT_WINDOW_272K: i64 = 272_000;
+1
View File
@@ -1,2 +1,3 @@
pub mod model_family;
pub mod model_presets;
pub mod models_manager;
@@ -8,11 +8,11 @@ use crate::truncate::TruncationPolicy;
/// The `instructions` field in the payload sent to a model should always start
/// with this content.
const BASE_INSTRUCTIONS: &str = include_str!("../prompt.md");
const BASE_INSTRUCTIONS: &str = include_str!("../../prompt.md");
const GPT_5_CODEX_INSTRUCTIONS: &str = include_str!("../gpt_5_codex_prompt.md");
const GPT_5_1_INSTRUCTIONS: &str = include_str!("../gpt_5_1_prompt.md");
const GPT_5_1_CODEX_MAX_INSTRUCTIONS: &str = include_str!("../gpt-5.1-codex-max_prompt.md");
const GPT_5_CODEX_INSTRUCTIONS: &str = include_str!("../../gpt_5_codex_prompt.md");
const GPT_5_1_INSTRUCTIONS: &str = include_str!("../../gpt_5_1_prompt.md");
const GPT_5_1_CODEX_MAX_INSTRUCTIONS: &str = include_str!("../../gpt-5.1-codex-max_prompt.md");
/// A model family is a group of models that share certain characteristics.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -100,13 +100,14 @@ macro_rules! model_family {
$(
mf.$key = $value;
)*
Some(mf)
mf
}};
}
// todo(aibrahim): remove this function
/// Returns a `ModelFamily` for the given model slug, or `None` if the slug
/// does not match any known model family.
pub fn find_family_for_model(slug: &str) -> Option<ModelFamily> {
pub fn find_family_for_model(slug: &str) -> ModelFamily {
if slug.starts_with("o3") {
model_family!(
slug, "o3",
@@ -238,11 +239,11 @@ pub fn find_family_for_model(slug: &str) -> Option<ModelFamily> {
truncation_policy: TruncationPolicy::Bytes(10_000),
)
} else {
None
derive_default_model_family(slug)
}
}
pub fn derive_default_model_family(model: &str) -> ModelFamily {
fn derive_default_model_family(model: &str) -> ModelFamily {
ModelFamily {
slug: model.to_string(),
family: model.to_string(),
@@ -2,6 +2,8 @@ use codex_app_server_protocol::AuthMode;
use codex_protocol::openai_models::ModelPreset;
use tokio::sync::RwLock;
use crate::openai_models::model_family::ModelFamily;
use crate::openai_models::model_family::find_family_for_model;
use crate::openai_models::model_presets::builtin_model_presets;
pub struct ModelsManager {
@@ -23,4 +25,8 @@ impl ModelsManager {
let models = builtin_model_presets(self.auth_mode);
*self.available_models.write().await = models;
}
pub fn construct_model_family(&self, model: &str) -> ModelFamily {
find_family_for_model(model)
}
}
+2
View File
@@ -3,6 +3,7 @@ use std::sync::Arc;
use crate::AuthManager;
use crate::RolloutRecorder;
use crate::mcp_connection_manager::McpConnectionManager;
use crate::openai_models::models_manager::ModelsManager;
use crate::tools::sandboxing::ApprovalStore;
use crate::unified_exec::UnifiedExecSessionManager;
use crate::user_notification::UserNotifier;
@@ -20,6 +21,7 @@ pub(crate) struct SessionServices {
pub(crate) user_shell: crate::shell::Shell,
pub(crate) show_raw_agent_reasoning: bool,
pub(crate) auth_manager: Arc<AuthManager>,
pub(crate) models_manager: Arc<ModelsManager>,
pub(crate) otel_event_manager: OtelEventManager,
pub(crate) tool_approvals: Mutex<ApprovalStore>,
}
+5
View File
@@ -19,6 +19,7 @@ use tracing::warn;
use crate::AuthManager;
use crate::codex::Session;
use crate::codex::TurnContext;
use crate::openai_models::models_manager::ModelsManager;
use crate::protocol::EventMsg;
use crate::protocol::TaskCompleteEvent;
use crate::protocol::TurnAbortReason;
@@ -55,6 +56,10 @@ impl SessionTaskContext {
pub(crate) fn auth_manager(&self) -> Arc<AuthManager> {
Arc::clone(&self.session.services.auth_manager)
}
pub(crate) fn models_manager(&self) -> Arc<ModelsManager> {
Arc::clone(&self.session.services.models_manager)
}
}
/// Async task that drives a [`Session`] turn.
+1
View File
@@ -93,6 +93,7 @@ async fn start_review_conversation(
(run_codex_conversation_one_shot(
sub_agent_config,
session.auth_manager(),
session.models_manager(),
input,
session.clone_session(),
ctx.clone(),
+14 -23
View File
@@ -2,7 +2,7 @@ use crate::client_common::tools::ResponsesApiTool;
use crate::client_common::tools::ToolSpec;
use crate::features::Feature;
use crate::features::Features;
use crate::model_family::ModelFamily;
use crate::openai_models::model_family::ModelFamily;
use crate::tools::handlers::PLAN_TOOL;
use crate::tools::handlers::apply_patch::ApplyPatchToolType;
use crate::tools::handlers::apply_patch::create_apply_patch_freeform_tool;
@@ -1118,7 +1118,7 @@ pub(crate) fn build_specs(
#[cfg(test)]
mod tests {
use crate::client_common::tools::FreeformTool;
use crate::model_family::find_family_for_model;
use crate::openai_models::model_family::find_family_for_model;
use crate::tools::registry::ConfiguredToolSpec;
use mcp_types::ToolInputSchema;
use pretty_assertions::assert_eq;
@@ -1213,8 +1213,7 @@ mod tests {
#[test]
fn test_full_toolset_specs_for_gpt5_codex_unified_exec_web_search() {
let model_family = find_family_for_model("gpt-5-codex")
.expect("gpt-5-codex should be a valid model family");
let model_family = find_family_for_model("gpt-5-codex");
let mut features = Features::with_defaults();
features.enable(Feature::UnifiedExec);
features.enable(Feature::WebSearchRequest);
@@ -1273,8 +1272,7 @@ mod tests {
}
fn assert_model_tools(model_family: &str, features: &Features, expected_tools: &[&str]) {
let model_family = find_family_for_model(model_family)
.unwrap_or_else(|| panic!("{model_family} should be a valid model family"));
let model_family = find_family_for_model(model_family);
let config = ToolsConfig::new(&ToolsConfigParams {
model_family: &model_family,
features,
@@ -1466,7 +1464,7 @@ mod tests {
#[test]
fn test_build_specs_default_shell_present() {
let model_family = find_family_for_model("o3").expect("o3 should be a valid model family");
let model_family = find_family_for_model("o3");
let mut features = Features::with_defaults();
features.enable(Feature::WebSearchRequest);
features.enable(Feature::UnifiedExec);
@@ -1487,8 +1485,7 @@ mod tests {
#[test]
#[ignore]
fn test_parallel_support_flags() {
let model_family = find_family_for_model("gpt-5-codex")
.expect("codex-mini-latest should be a valid model family");
let model_family = find_family_for_model("gpt-5-codex");
let mut features = Features::with_defaults();
features.disable(Feature::ViewImageTool);
features.enable(Feature::UnifiedExec);
@@ -1507,8 +1504,7 @@ mod tests {
#[test]
fn test_test_model_family_includes_sync_tool() {
let model_family = find_family_for_model("test-gpt-5-codex")
.expect("test-gpt-5-codex should be a valid model family");
let model_family = find_family_for_model("test-gpt-5-codex");
let mut features = Features::with_defaults();
features.disable(Feature::ViewImageTool);
let config = ToolsConfig::new(&ToolsConfigParams {
@@ -1537,7 +1533,7 @@ mod tests {
#[test]
fn test_build_specs_mcp_tools_converted() {
let model_family = find_family_for_model("o3").expect("o3 should be a valid model family");
let model_family = find_family_for_model("o3");
let mut features = Features::with_defaults();
features.enable(Feature::UnifiedExec);
features.enable(Feature::WebSearchRequest);
@@ -1631,7 +1627,7 @@ mod tests {
#[test]
fn test_build_specs_mcp_tools_sorted_by_name() {
let model_family = find_family_for_model("o3").expect("o3 should be a valid model family");
let model_family = find_family_for_model("o3");
let mut features = Features::with_defaults();
features.enable(Feature::UnifiedExec);
let config = ToolsConfig::new(&ToolsConfigParams {
@@ -1706,8 +1702,7 @@ mod tests {
#[test]
fn test_mcp_tool_property_missing_type_defaults_to_string() {
let model_family = find_family_for_model("gpt-5-codex")
.expect("gpt-5-codex should be a valid model family");
let model_family = find_family_for_model("gpt-5-codex");
let mut features = Features::with_defaults();
features.enable(Feature::UnifiedExec);
features.enable(Feature::WebSearchRequest);
@@ -1763,8 +1758,7 @@ mod tests {
#[test]
fn test_mcp_tool_integer_normalized_to_number() {
let model_family = find_family_for_model("gpt-5-codex")
.expect("gpt-5-codex should be a valid model family");
let model_family = find_family_for_model("gpt-5-codex");
let mut features = Features::with_defaults();
features.enable(Feature::UnifiedExec);
features.enable(Feature::WebSearchRequest);
@@ -1816,8 +1810,7 @@ mod tests {
#[test]
fn test_mcp_tool_array_without_items_gets_default_string_items() {
let model_family = find_family_for_model("gpt-5-codex")
.expect("gpt-5-codex should be a valid model family");
let model_family = find_family_for_model("gpt-5-codex");
let mut features = Features::with_defaults();
features.enable(Feature::UnifiedExec);
features.enable(Feature::WebSearchRequest);
@@ -1873,8 +1866,7 @@ mod tests {
#[test]
fn test_mcp_tool_anyof_defaults_to_string() {
let model_family = find_family_for_model("gpt-5-codex")
.expect("gpt-5-codex should be a valid model family");
let model_family = find_family_for_model("gpt-5-codex");
let mut features = Features::with_defaults();
features.enable(Feature::UnifiedExec);
features.enable(Feature::WebSearchRequest);
@@ -1985,8 +1977,7 @@ Examples of valid command strings:
#[test]
fn test_get_openai_tools_mcp_tools_with_additional_properties_schema() {
let model_family = find_family_for_model("gpt-5-codex")
.expect("gpt-5-codex should be a valid model family");
let model_family = find_family_for_model("gpt-5-codex");
let mut features = Features::with_defaults();
features.enable(Feature::UnifiedExec);
features.enable(Feature::WebSearchRequest);
-2
View File
@@ -11,7 +11,6 @@ use codex_core::ModelProviderInfo;
use codex_core::built_in_model_providers;
use codex_core::config::Config;
use codex_core::features::Feature;
use codex_core::model_family::find_family_for_model;
use codex_core::protocol::AskForApproval;
use codex_core::protocol::EventMsg;
use codex_core::protocol::Op;
@@ -71,7 +70,6 @@ impl TestCodexBuilder {
let new_model = model.to_string();
self.with_config(move |config| {
config.model = new_model.clone();
config.model_family = find_family_for_model(&new_model).expect("model family");
})
}
+2 -3
View File
@@ -16,7 +16,7 @@ use codex_core::auth::AuthCredentialsStoreMode;
use codex_core::built_in_model_providers;
use codex_core::error::CodexErr;
use codex_core::features::Feature;
use codex_core::model_family::find_family_for_model;
use codex_core::openai_models::model_family::find_family_for_model;
use codex_core::protocol::EventMsg;
use codex_core::protocol::Op;
use codex_core::protocol::SessionSource;
@@ -1378,8 +1378,7 @@ async fn context_window_error_sets_total_tokens_to_model_window() -> anyhow::Res
let TestCodex { codex, .. } = test_codex()
.with_config(|config| {
config.model = "gpt-5.1".to_string();
config.model_family =
find_family_for_model("gpt-5.1").expect("known gpt-5.1 model family");
config.model_family = find_family_for_model("gpt-5.1");
config.model_context_window = Some(272_000);
})
.build(&server)
+1 -2
View File
@@ -1,7 +1,7 @@
#![allow(clippy::unwrap_used)]
use codex_core::features::Feature;
use codex_core::model_family::find_family_for_model;
use codex_core::openai_models::model_family::find_family_for_model;
use codex_core::protocol::AskForApproval;
use codex_core::protocol::ENVIRONMENT_CONTEXT_OPEN_TAG;
use codex_core::protocol::EventMsg;
@@ -74,7 +74,6 @@ async fn codex_mini_latest_tools() -> anyhow::Result<()> {
config.features.disable(Feature::ApplyPatchFreeform);
config.model = "codex-mini-latest".to_string();
config.model_family = find_family_for_model("codex-mini-latest")
.expect("model family for codex-mini-latest");
})
.build(&server)
.await?;
@@ -4,7 +4,7 @@
use anyhow::Result;
use codex_core::config::Config;
use codex_core::features::Feature;
use codex_core::model_family::find_family_for_model;
use codex_core::openai_models::model_family::find_family_for_model;
use codex_core::protocol::SandboxPolicy;
use core_test_support::assert_regex_match;
use core_test_support::responses::ev_assistant_message;
@@ -46,13 +46,12 @@ fn configure_shell_command_model(output_type: ShellModelOutput, config: &mut Con
return;
}
if let Some(shell_command_family) = find_family_for_model("test-gpt-5-codex") {
if config.model_family.shell_type == shell_command_family.shell_type {
return;
}
config.model = shell_command_family.slug.clone();
config.model_family = shell_command_family;
let shell_command_family = find_family_for_model("test-gpt-5-codex");
if config.model_family.shell_type == shell_command_family.shell_type {
return;
}
config.model = shell_command_family.slug.clone();
config.model_family = shell_command_family;
}
fn shell_responses(
+4 -7
View File
@@ -26,7 +26,7 @@ use codex_core::ConversationManager;
use codex_core::config::Config;
use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::features::Feature;
use codex_core::model_family::find_family_for_model;
use codex_core::openai_models::model_family::find_family_for_model;
use codex_core::openai_models::model_presets::HIDE_GPT_5_1_CODEX_MAX_MIGRATION_PROMPT_CONFIG;
use codex_core::openai_models::model_presets::HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG;
use codex_core::openai_models::models_manager::ModelsManager;
@@ -162,9 +162,7 @@ async fn handle_model_migration_prompt_if_needed(
migration_config: migration_config_key.to_string(),
});
config.model = target_model.to_string();
if let Some(family) = find_family_for_model(&target_model) {
config.model_family = family;
}
config.model_family = find_family_for_model(&target_model);
let mapped_effort = if let Some(reasoning_effort_mapping) = reasoning_effort_mapping
&& let Some(reasoning_effort) = config.model_reasoning_effort
@@ -683,9 +681,8 @@ impl App {
AppEvent::UpdateModel(model) => {
self.chat_widget.set_model(&model);
self.config.model = model.clone();
if let Some(family) = find_family_for_model(&model) {
self.config.model_family = family;
}
let family = find_family_for_model(&model);
self.config.model_family = family;
}
AppEvent::OpenReasoningPopup { model } => {
self.chat_widget.open_reasoning_popup(model);