mirror of
https://github.com/openai/codex.git
synced 2026-04-30 09:26:44 +00:00
Add max context window model metadata (#18382)
Adds max_context_window to model metadata and routes core context-window reads through resolved model info. Config model_context_window overrides are clamped to max_context_window when present; without an override, the model context_window is used.
This commit is contained in:
@@ -97,6 +97,7 @@ fn test_model_info(
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(272_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
@@ -914,6 +915,7 @@ async fn model_switch_to_smaller_model_updates_token_context_window() -> Result<
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(large_context_window),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
|
||||
@@ -350,6 +350,7 @@ fn test_remote_model(slug: &str, priority: i32) -> ModelInfo {
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(272_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
|
||||
@@ -666,6 +666,7 @@ async fn remote_model_friendly_personality_instructions_with_feature() -> anyhow
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(128_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
@@ -783,6 +784,7 @@ async fn user_turn_personality_remote_model_template_includes_update_message() -
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(128_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
|
||||
@@ -116,6 +116,233 @@ async fn remote_models_get_model_info_uses_longest_matching_prefix() -> Result<(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Scenario: the model advertises a default 273k context window and a 400k max
|
||||
/// context window, and the user explicitly configures 1M. This verifies the
|
||||
/// runtime turn clamps the override to the advertised max window.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn remote_models_config_context_window_override_clamps_to_max_context_window() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
skip_if_sandbox!(Ok(()));
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let requested_model = "gpt-5.4-test";
|
||||
let mut remote_model =
|
||||
test_remote_model("gpt-5.4", ModelVisibility::List, /*priority*/ 1_000);
|
||||
remote_model.context_window = Some(273_000);
|
||||
remote_model.max_context_window = Some(400_000);
|
||||
remote_model.effective_context_window_percent = 100;
|
||||
mount_models_once(
|
||||
&server,
|
||||
ModelsResponse {
|
||||
models: vec![remote_model],
|
||||
},
|
||||
)
|
||||
.await;
|
||||
mount_sse_once(
|
||||
&server,
|
||||
sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]),
|
||||
)
|
||||
.await;
|
||||
|
||||
let TestCodex {
|
||||
codex, cwd, config, ..
|
||||
} = test_codex()
|
||||
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_config(|config| {
|
||||
config.model = Some(requested_model.to_string());
|
||||
config.model_context_window = Some(1_000_000);
|
||||
})
|
||||
.build(&server)
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
items: vec![UserInput::Text {
|
||||
text: "check context window".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
final_output_json_schema: None,
|
||||
cwd: cwd.path().to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
model: requested_model.to_string(),
|
||||
effort: None,
|
||||
summary: None,
|
||||
service_tier: None,
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let turn_started_event = wait_for_event(&codex, |event| {
|
||||
matches!(
|
||||
event,
|
||||
EventMsg::TurnStarted(started)
|
||||
if started.model_context_window == Some(400_000)
|
||||
)
|
||||
})
|
||||
.await;
|
||||
let EventMsg::TurnStarted(turn_started) = turn_started_event else {
|
||||
unreachable!("wait_for_event returned unexpected event");
|
||||
};
|
||||
|
||||
assert_eq!(turn_started.model_context_window, Some(400_000));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Scenario: the user explicitly configures a context window above the model's
|
||||
/// max_context_window. This verifies the runtime window is clamped to the max
|
||||
/// instead of using the oversized config value.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn remote_models_config_override_above_max_uses_max_context_window() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
skip_if_sandbox!(Ok(()));
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let requested_model = "gpt-5.4-test";
|
||||
let mut remote_model =
|
||||
test_remote_model("gpt-5.4", ModelVisibility::List, /*priority*/ 1_000);
|
||||
remote_model.context_window = Some(273_000);
|
||||
remote_model.max_context_window = Some(400_000);
|
||||
remote_model.effective_context_window_percent = 100;
|
||||
mount_models_once(
|
||||
&server,
|
||||
ModelsResponse {
|
||||
models: vec![remote_model],
|
||||
},
|
||||
)
|
||||
.await;
|
||||
mount_sse_once(
|
||||
&server,
|
||||
sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]),
|
||||
)
|
||||
.await;
|
||||
|
||||
let TestCodex {
|
||||
codex, cwd, config, ..
|
||||
} = test_codex()
|
||||
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_config(|config| {
|
||||
config.model = Some(requested_model.to_string());
|
||||
config.model_context_window = Some(500_000);
|
||||
})
|
||||
.build(&server)
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
items: vec![UserInput::Text {
|
||||
text: "check context window".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
final_output_json_schema: None,
|
||||
cwd: cwd.path().to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
model: requested_model.to_string(),
|
||||
effort: None,
|
||||
summary: None,
|
||||
service_tier: None,
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let turn_started_event = wait_for_event(&codex, |event| {
|
||||
matches!(
|
||||
event,
|
||||
EventMsg::TurnStarted(started)
|
||||
if started.model_context_window == Some(400_000)
|
||||
)
|
||||
})
|
||||
.await;
|
||||
let EventMsg::TurnStarted(turn_started) = turn_started_event else {
|
||||
unreachable!("wait_for_event returned unexpected event");
|
||||
};
|
||||
|
||||
assert_eq!(turn_started.model_context_window, Some(400_000));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Scenario: model metadata includes both context_window and max_context_window,
|
||||
/// but the user did not configure an override. This verifies the runtime keeps
|
||||
/// using the model's default context_window in the no-override path.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn remote_models_use_context_window_when_config_override_is_absent() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
skip_if_sandbox!(Ok(()));
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let requested_model = "gpt-5.4-test";
|
||||
let mut remote_model =
|
||||
test_remote_model("gpt-5.4", ModelVisibility::List, /*priority*/ 1_000);
|
||||
remote_model.context_window = Some(273_000);
|
||||
remote_model.max_context_window = Some(400_000);
|
||||
remote_model.effective_context_window_percent = 100;
|
||||
mount_models_once(
|
||||
&server,
|
||||
ModelsResponse {
|
||||
models: vec![remote_model],
|
||||
},
|
||||
)
|
||||
.await;
|
||||
mount_sse_once(
|
||||
&server,
|
||||
sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]),
|
||||
)
|
||||
.await;
|
||||
|
||||
let TestCodex {
|
||||
codex, cwd, config, ..
|
||||
} = test_codex()
|
||||
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_config(|config| {
|
||||
config.model = Some(requested_model.to_string());
|
||||
})
|
||||
.build(&server)
|
||||
.await?;
|
||||
|
||||
codex
|
||||
.submit(Op::UserTurn {
|
||||
items: vec![UserInput::Text {
|
||||
text: "check context window".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
final_output_json_schema: None,
|
||||
cwd: cwd.path().to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
model: requested_model.to_string(),
|
||||
effort: None,
|
||||
summary: None,
|
||||
service_tier: None,
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let turn_started_event = wait_for_event(&codex, |event| {
|
||||
matches!(
|
||||
event,
|
||||
EventMsg::TurnStarted(started)
|
||||
if started.model_context_window == Some(273_000)
|
||||
)
|
||||
})
|
||||
.await;
|
||||
let EventMsg::TurnStarted(turn_started) = turn_started_event else {
|
||||
unreachable!("wait_for_event returned unexpected event");
|
||||
};
|
||||
|
||||
assert_eq!(turn_started.model_context_window, Some(273_000));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn remote_models_long_model_slug_is_sent_with_high_reasoning() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
@@ -312,6 +539,7 @@ async fn remote_models_remote_model_uses_unified_exec() -> Result<()> {
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(272_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
@@ -561,6 +789,7 @@ async fn remote_models_apply_remote_base_instructions() -> Result<()> {
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(272_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
@@ -1044,6 +1273,7 @@ fn test_remote_model_with_policy(
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(272_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
|
||||
@@ -1020,6 +1020,7 @@ async fn stdio_image_responses_are_sanitized_for_text_only_model() -> anyhow::Re
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(272_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
|
||||
@@ -82,6 +82,7 @@ fn test_model_info(
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(272_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
|
||||
@@ -1365,6 +1365,7 @@ async fn view_image_tool_returns_unsupported_message_for_text_only_model() -> an
|
||||
supports_parallel_tool_calls: false,
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(272_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
|
||||
Reference in New Issue
Block a user