extract models manager and related ownership from core (#16508)

## Summary
- split `models-manager` out of `core` and add `ModelsManagerConfig`
plus `Config::to_models_manager_config()` so model metadata paths stop
depending on `core::Config`
- move login-owned/auth-owned code out of `core` into `codex-login`,
move model provider config into `codex-model-provider-info`, move API
bridge mapping into `codex-api`, move protocol-owned types/impls into
`codex-protocol`, and move response debug helpers into a dedicated
`response-debug-context` crate
- move feedback tag emission into `codex-feedback`, relocate tests to
the crates that now own the code, and keep broad temporary re-exports so
this PR avoids a giant import-only rewrite

## Major moves and decisions
- created `codex-models-manager` as the owner for model
cache/catalog/config/model info logic, including the new
`ModelsManagerConfig` struct
- created `codex-model-provider-info` as the owner for provider config
parsing/defaults and kept temporary `codex-login`/`codex-core`
re-exports for old import paths
- moved `api_bridge` error mapping + `CoreAuthProvider` into
`codex-api`, while `codex-login::api_bridge` temporarily re-exports
those symbols and keeps the `auth_provider_from_auth` wrapper
- moved `auth_env_telemetry` and `provider_auth` ownership to
`codex-login`
- moved `CodexErr` ownership to `codex-protocol::error`, plus
`StreamOutput`, `bytes_to_string_smart`, and network policy helpers to
protocol-owned modules
- created `codex-response-debug-context` for
`extract_response_debug_context`, `telemetry_transport_error_message`,
and related response-debug plumbing instead of leaving that behavior in
`core`
- moved `FeedbackRequestTags`, `emit_feedback_request_tags`, and
`emit_feedback_request_tags_with_auth_env` to `codex-feedback`
- deferred removal of temporary re-exports and the mechanical import
rewrites to a stacked follow-up PR so this PR stays reviewable

## Test moves
- moved auth refresh coverage from `core/tests/suite/auth_refresh.rs` to
`login/tests/suite/auth_refresh.rs`
- moved text encoding coverage from
`core/tests/suite/text_encoding_fix.rs` to
`protocol/src/exec_output_tests.rs`
- moved model info override coverage from
`core/tests/suite/model_info_overrides.rs` to
`models-manager/src/model_info_overrides_tests.rs`

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Ahmed Ibrahim
2026-04-02 23:00:02 -07:00
committed by GitHub
parent 8cd7f20b48
commit 6fff9955f1
99 changed files with 1095 additions and 1137 deletions

View File

@@ -9,12 +9,12 @@ use crate::config_loader::NetworkDomainPermissionsToml;
use crate::config_loader::RequirementSource;
use crate::config_loader::Sourced;
use crate::exec::ExecCapturePolicy;
use crate::exec::ExecToolCallOutput;
use crate::function_tool::FunctionCallError;
use crate::models_manager::model_info;
use crate::shell::default_user_shell;
use crate::tools::format_exec_output_str;
use crate::exec::ExecToolCallOutput;
use codex_features::Features;
use codex_login::CodexAuth;
use codex_mcp::mcp_connection_manager::ToolInfo;
@@ -63,7 +63,6 @@ use codex_protocol::models::ContentItem;
use codex_protocol::models::DeveloperInstructions;
use codex_protocol::models::ResponseInputItem;
use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::ModelsResponse;
use codex_protocol::protocol::AskForApproval;
use codex_protocol::protocol::CompactedItem;
use codex_protocol::protocol::ConversationAudioParams;
@@ -532,8 +531,8 @@ async fn start_managed_network_proxy_ignores_invalid_execpolicy_network_rules()
async fn get_base_instructions_no_user_content() {
let prompt_with_apply_patch_instructions =
include_str!("../prompt_with_apply_patch_instructions.md");
let models_response: ModelsResponse =
serde_json::from_str(include_str!("../models.json")).expect("valid models.json");
let models_response = codex_models_manager::bundled_models_response()
.unwrap_or_else(|err| panic!("bundled models.json should parse: {err}"));
let model_info_for_slug = |slug: &str, config: &Config| {
let model = models_response
.models
@@ -541,7 +540,7 @@ async fn get_base_instructions_no_user_content() {
.find(|candidate| candidate.slug == slug)
.cloned()
.unwrap_or_else(|| panic!("model slug {slug} is missing from models.json"));
model_info::with_config_overrides(model, config)
model_info::with_config_overrides(model, &config.to_models_manager_config())
};
let test_cases = vec![
InstructionsTestCase {
@@ -1789,7 +1788,10 @@ async fn set_rate_limits_retains_previous_credits() {
let config = build_test_config(codex_home.path()).await;
let config = Arc::new(config);
let model = ModelsManager::get_model_offline_for_tests(config.model.as_deref());
let model_info = ModelsManager::construct_model_info_offline_for_tests(model.as_str(), &config);
let model_info = ModelsManager::construct_model_info_offline_for_tests(
model.as_str(),
&config.to_models_manager_config(),
);
let reasoning_effort = config.model_reasoning_effort;
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
@@ -1887,7 +1889,10 @@ async fn set_rate_limits_updates_plan_type_when_present() {
let config = build_test_config(codex_home.path()).await;
let config = Arc::new(config);
let model = ModelsManager::get_model_offline_for_tests(config.model.as_deref());
let model_info = ModelsManager::construct_model_info_offline_for_tests(model.as_str(), &config);
let model_info = ModelsManager::construct_model_info_offline_for_tests(
model.as_str(),
&config.to_models_manager_config(),
);
let reasoning_effort = config.model_reasoning_effort;
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
@@ -2037,7 +2042,10 @@ async fn turn_context_with_model_updates_model_fields() {
let expected_model_info = session
.services
.models_manager
.get_model_info("gpt-5.1", updated.config.as_ref())
.get_model_info(
"gpt-5.1",
&updated.config.as_ref().to_models_manager_config(),
)
.await;
assert_eq!(updated.config.model.as_deref(), Some("gpt-5.1"));
@@ -2228,7 +2236,10 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
let config = build_test_config(codex_home.path()).await;
let config = Arc::new(config);
let model = ModelsManager::get_model_offline_for_tests(config.model.as_deref());
let model_info = ModelsManager::construct_model_info_offline_for_tests(model.as_str(), &config);
let model_info = ModelsManager::construct_model_info_offline_for_tests(
model.as_str(),
&config.to_models_manager_config(),
);
let reasoning_effort = config.model_reasoning_effort;
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
@@ -2492,7 +2503,10 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
CollaborationModesConfig::default(),
));
let model = ModelsManager::get_model_offline_for_tests(config.model.as_deref());
let model_info = ModelsManager::construct_model_info_offline_for_tests(model.as_str(), &config);
let model_info = ModelsManager::construct_model_info_offline_for_tests(
model.as_str(),
&config.to_models_manager_config(),
);
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
settings: Settings {
@@ -2588,7 +2602,10 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
let exec_policy = Arc::new(ExecPolicyManager::default());
let (agent_status_tx, _agent_status_rx) = watch::channel(AgentStatus::PendingInit);
let model = ModelsManager::get_model_offline_for_tests(config.model.as_deref());
let model_info = ModelsManager::construct_model_info_offline_for_tests(model.as_str(), &config);
let model_info = ModelsManager::construct_model_info_offline_for_tests(
model.as_str(),
&config.to_models_manager_config(),
);
let reasoning_effort = config.model_reasoning_effort;
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
@@ -2632,7 +2649,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
let per_turn_config = Session::build_per_turn_config(&session_configuration);
let model_info = ModelsManager::construct_model_info_offline_for_tests(
session_configuration.collaboration_mode.model(),
&per_turn_config,
&per_turn_config.to_models_manager_config(),
);
let session_telemetry = session_telemetry(
conversation_id,
@@ -3424,7 +3441,10 @@ pub(crate) async fn make_session_and_context_with_dynamic_tools_and_rx(
let exec_policy = Arc::new(ExecPolicyManager::default());
let (agent_status_tx, _agent_status_rx) = watch::channel(AgentStatus::PendingInit);
let model = ModelsManager::get_model_offline_for_tests(config.model.as_deref());
let model_info = ModelsManager::construct_model_info_offline_for_tests(model.as_str(), &config);
let model_info = ModelsManager::construct_model_info_offline_for_tests(
model.as_str(),
&config.to_models_manager_config(),
);
let reasoning_effort = config.model_reasoning_effort;
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
@@ -3468,7 +3488,7 @@ pub(crate) async fn make_session_and_context_with_dynamic_tools_and_rx(
let per_turn_config = Session::build_per_turn_config(&session_configuration);
let model_info = ModelsManager::construct_model_info_offline_for_tests(
session_configuration.collaboration_mode.model(),
&per_turn_config,
&per_turn_config.to_models_manager_config(),
);
let session_telemetry = session_telemetry(
conversation_id,