mirror of
https://github.com/openai/codex.git
synced 2026-05-05 03:47:01 +00:00
Load models from static file (#8153)
- Load models from static file as a fallback - Make API users use this file directly - Add tests to make sure updates to the file always serialize
This commit is contained in:
@@ -762,7 +762,7 @@ async fn includes_configured_effort_in_request() -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn includes_no_effort_in_request() -> anyhow::Result<()> {
|
||||
async fn includes_default_effort_in_request() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
let server = MockServer::start().await;
|
||||
|
||||
@@ -791,7 +791,7 @@ async fn includes_no_effort_in_request() -> anyhow::Result<()> {
|
||||
.get("reasoning")
|
||||
.and_then(|t| t.get("effort"))
|
||||
.and_then(|v| v.as_str()),
|
||||
None
|
||||
Some("medium")
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -276,6 +276,7 @@ async fn compact_resume_and_fork_preserve_model_history_view() {
|
||||
"tool_choice": "auto",
|
||||
"parallel_tool_calls": false,
|
||||
"reasoning": {
|
||||
"effort": "medium",
|
||||
"summary": "auto"
|
||||
},
|
||||
"store": false,
|
||||
@@ -345,6 +346,7 @@ async fn compact_resume_and_fork_preserve_model_history_view() {
|
||||
"tool_choice": "auto",
|
||||
"parallel_tool_calls": false,
|
||||
"reasoning": {
|
||||
"effort": "medium",
|
||||
"summary": "auto"
|
||||
},
|
||||
"store": false,
|
||||
@@ -405,6 +407,7 @@ async fn compact_resume_and_fork_preserve_model_history_view() {
|
||||
"tool_choice": "auto",
|
||||
"parallel_tool_calls": false,
|
||||
"reasoning": {
|
||||
"effort": "medium",
|
||||
"summary": "auto"
|
||||
},
|
||||
"store": false,
|
||||
@@ -485,6 +488,7 @@ async fn compact_resume_and_fork_preserve_model_history_view() {
|
||||
"tool_choice": "auto",
|
||||
"parallel_tool_calls": false,
|
||||
"reasoning": {
|
||||
"effort": "medium",
|
||||
"summary": "auto"
|
||||
},
|
||||
"store": false,
|
||||
@@ -565,6 +569,7 @@ async fn compact_resume_and_fork_preserve_model_history_view() {
|
||||
"tool_choice": "auto",
|
||||
"parallel_tool_calls": false,
|
||||
"reasoning": {
|
||||
"effort": "medium",
|
||||
"summary": "auto"
|
||||
},
|
||||
"store": false,
|
||||
|
||||
@@ -114,7 +114,14 @@ fn gpt_5_1_codex() -> ModelPreset {
|
||||
),
|
||||
],
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_5_1_codex_max_upgrade()),
|
||||
upgrade: Some(gpt_5_1_codex_max_upgrade(
|
||||
"gpt-5.1-codex",
|
||||
vec![
|
||||
ReasoningEffort::Low,
|
||||
ReasoningEffort::Medium,
|
||||
ReasoningEffort::High,
|
||||
],
|
||||
)),
|
||||
show_in_picker: true,
|
||||
}
|
||||
}
|
||||
@@ -137,7 +144,10 @@ fn gpt_5_1_codex_mini() -> ModelPreset {
|
||||
),
|
||||
],
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_5_1_codex_max_upgrade()),
|
||||
upgrade: Some(gpt_5_1_codex_max_upgrade(
|
||||
"gpt-5.1-codex-mini",
|
||||
vec![ReasoningEffort::Medium, ReasoningEffort::High],
|
||||
)),
|
||||
show_in_picker: true,
|
||||
}
|
||||
}
|
||||
@@ -162,7 +172,7 @@ fn gpt_5_2() -> ModelPreset {
|
||||
),
|
||||
effort(
|
||||
ReasoningEffort::High,
|
||||
"Greater reasoning depth for complex or ambiguous problems",
|
||||
"Maximizes reasoning depth for complex or ambiguous problems",
|
||||
),
|
||||
effort(
|
||||
ReasoningEffort::XHigh,
|
||||
@@ -197,16 +207,59 @@ fn gpt_5_1() -> ModelPreset {
|
||||
),
|
||||
],
|
||||
is_default: false,
|
||||
upgrade: Some(gpt_5_1_codex_max_upgrade()),
|
||||
upgrade: Some(gpt_5_1_codex_max_upgrade(
|
||||
"gpt-5.1",
|
||||
vec![
|
||||
ReasoningEffort::Low,
|
||||
ReasoningEffort::Medium,
|
||||
ReasoningEffort::High,
|
||||
],
|
||||
)),
|
||||
show_in_picker: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn gpt_5_1_codex_max_upgrade() -> codex_protocol::openai_models::ModelUpgrade {
|
||||
fn gpt_5_1_codex_max_upgrade(
|
||||
migration_config_key: &str,
|
||||
supported_efforts: Vec<ReasoningEffort>,
|
||||
) -> codex_protocol::openai_models::ModelUpgrade {
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn nearest_effort(effort: ReasoningEffort, supported: &[ReasoningEffort]) -> ReasoningEffort {
|
||||
supported
|
||||
.iter()
|
||||
.min_by_key(|candidate| (effort_rank(effort) - effort_rank(**candidate)).abs())
|
||||
.copied()
|
||||
.unwrap_or(ReasoningEffort::Low)
|
||||
}
|
||||
|
||||
fn effort_rank(effort: ReasoningEffort) -> i32 {
|
||||
match effort {
|
||||
ReasoningEffort::None => 0,
|
||||
ReasoningEffort::Minimal => 1,
|
||||
ReasoningEffort::Low => 2,
|
||||
ReasoningEffort::Medium => 3,
|
||||
ReasoningEffort::High => 4,
|
||||
ReasoningEffort::XHigh => 5,
|
||||
}
|
||||
}
|
||||
|
||||
let mut mapping = HashMap::new();
|
||||
for effort in [
|
||||
ReasoningEffort::None,
|
||||
ReasoningEffort::Minimal,
|
||||
ReasoningEffort::Low,
|
||||
ReasoningEffort::Medium,
|
||||
ReasoningEffort::High,
|
||||
ReasoningEffort::XHigh,
|
||||
] {
|
||||
mapping.insert(effort, nearest_effort(effort, &supported_efforts));
|
||||
}
|
||||
|
||||
codex_protocol::openai_models::ModelUpgrade {
|
||||
id: "gpt-5.1-codex-max".to_string(),
|
||||
reasoning_effort_mapping: None,
|
||||
migration_config_key: "hide_gpt-5.1-codex-max_migration_prompt".to_string(),
|
||||
reasoning_effort_mapping: Some(mapping),
|
||||
migration_config_key: migration_config_key.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,60 +59,8 @@ fn assert_tool_names(body: &serde_json::Value, expected_names: &[&str]) {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn codex_mini_latest_tools() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let req1 = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let req2 = mount_sse_once(&server, sse_completed("resp-2")).await;
|
||||
|
||||
let TestCodex { codex, .. } = test_codex()
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some("be consistent and helpful".to_string());
|
||||
config.features.disable(Feature::ApplyPatchFreeform);
|
||||
config.model = Some("codex-mini-latest".to_string());
|
||||
})
|
||||
.build(&server)
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
}],
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
}],
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
|
||||
|
||||
let expected_instructions = [
|
||||
include_str!("../../prompt.md"),
|
||||
include_str!("../../../apply-patch/apply_patch_tool_instructions.md"),
|
||||
]
|
||||
.join("\n");
|
||||
|
||||
let body0 = req1.single_request().body_json();
|
||||
assert_eq!(
|
||||
body0["instructions"],
|
||||
serde_json::json!(expected_instructions),
|
||||
);
|
||||
let body1 = req2.single_request().body_json();
|
||||
assert_eq!(
|
||||
body1["instructions"],
|
||||
serde_json::json!(expected_instructions),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
fn normalize_newlines(text: &str) -> String {
|
||||
text.replace("\r\n", "\n")
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
@@ -204,6 +152,70 @@ async fn prompt_tools_are_consistent_across_requests() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn codex_mini_latest_tools() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let req1 = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let req2 = mount_sse_once(&server, sse_completed("resp-2")).await;
|
||||
|
||||
let TestCodex { codex, .. } = test_codex()
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some("be consistent and helpful".to_string());
|
||||
config.features.disable(Feature::ApplyPatchFreeform);
|
||||
config.model = Some("codex-mini-latest".to_string());
|
||||
})
|
||||
.build(&server)
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
}],
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
}],
|
||||
})
|
||||
.await?;
|
||||
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
|
||||
|
||||
let expected_instructions = [
|
||||
include_str!("../../prompt.md"),
|
||||
include_str!("../../../apply-patch/apply_patch_tool_instructions.md"),
|
||||
]
|
||||
.join("\n");
|
||||
|
||||
let body0 = req1.single_request().body_json();
|
||||
let instructions0 = body0["instructions"]
|
||||
.as_str()
|
||||
.expect("instructions should be a string");
|
||||
assert_eq!(
|
||||
normalize_newlines(instructions0),
|
||||
normalize_newlines(&expected_instructions)
|
||||
);
|
||||
|
||||
let body1 = req2.single_request().body_json();
|
||||
let instructions1 = body1["instructions"]
|
||||
.as_str()
|
||||
.expect("instructions should be a string");
|
||||
assert_eq!(
|
||||
normalize_newlines(instructions1),
|
||||
normalize_newlines(&expected_instructions)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn prefixes_context_and_instructions_once_and_consistently_across_requests()
|
||||
-> anyhow::Result<()> {
|
||||
|
||||
@@ -319,7 +319,7 @@ async fn remote_models_preserve_builtin_presets() -> Result<()> {
|
||||
let mut config = load_default_config_for_test(&codex_home);
|
||||
config.features.enable(Feature::RemoteModels);
|
||||
|
||||
let auth = CodexAuth::from_api_key("dummy");
|
||||
let auth = CodexAuth::create_dummy_chatgpt_auth_for_testing();
|
||||
let provider = ModelProviderInfo {
|
||||
base_url: Some(format!("{}/v1", server.uri())),
|
||||
..built_in_model_providers()["openai"].clone()
|
||||
@@ -436,7 +436,7 @@ async fn build_remote_models_harness<F>(
|
||||
where
|
||||
F: FnOnce(&mut Config),
|
||||
{
|
||||
let auth = CodexAuth::from_api_key("dummy");
|
||||
let auth = CodexAuth::create_dummy_chatgpt_auth_for_testing();
|
||||
let home = Arc::new(TempDir::new()?);
|
||||
let cwd = Arc::new(TempDir::new()?);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user