mirror of
https://github.com/openai/codex.git
synced 2026-11-07 08:34:29 +00:00
Remove retired model entries while preserving migration prompts (#44250)
## Why Saved model selections can outlive their bundled catalog entries and still need migration guidance. ## What changed - Remove `gpt-5.2` and `gpt-5.4-mini` from the bundled model catalog. - Preserve migration from saved `gpt-5.4-mini` selections to `gpt-5.6-luna` when the old model is absent, while respecting catalog-provided migration metadata. - Update tests and snapshots to use current models or explicit test fixtures, and remove the obsolete prompt fixture. ## Testing Extend migration tests to cover catalog metadata precedence, saved selections, replacement model and reasoning-effort persistence, acknowledged prompts, and missing or hidden migration targets. GitOrigin-RevId: 82beea504cc4a15699677c28a61ec0939af3069c
This commit is contained in:
1 parent
6eecd04fc1
commit
eb7bd64ef9
58 files changed
+670
-1192
No files matched your search
@@ -9,7 +9,6 @@ use codex_core::config::Constrained;
|
||||
use codex_core::config::ThreadStoreConfig;
|
||||
use codex_core::sandboxing::SandboxPermissions;
|
||||
use codex_features::Feature;
|
||||
use codex_models_manager::bundled_models_response;
|
||||
use codex_protocol::approvals::NetworkApprovalProtocol;
|
||||
use codex_protocol::approvals::NetworkPolicyAmendment;
|
||||
use codex_protocol::approvals::NetworkPolicyRuleAction;
|
||||
@@ -644,7 +643,6 @@ struct ScenarioSpec {
|
||||
action: ActionKind,
|
||||
sandbox_permissions: SandboxPermissions,
|
||||
features: Vec<Feature>,
|
||||
model_override: Option<&'static str>,
|
||||
outcome: Outcome,
|
||||
expectation: Expectation,
|
||||
}
|
||||
@@ -927,7 +925,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileCreated {
|
||||
target: TargetPath::OutsideWorkspace("dfa_on_request.txt"),
|
||||
@@ -944,7 +941,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileCreated {
|
||||
target: TargetPath::OutsideWorkspace("dfa_on_request_5_1.txt"),
|
||||
@@ -961,7 +957,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::NetworkSuccess {
|
||||
body_contains: "danger-network-ok",
|
||||
@@ -977,7 +972,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::NetworkSuccessNoExitCode {
|
||||
body_contains: "danger-network-ok",
|
||||
@@ -992,7 +986,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("blocked in untrusted project"),
|
||||
expected_reason: None,
|
||||
@@ -1010,7 +1003,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("blocked in untrusted project"),
|
||||
expected_reason: None,
|
||||
@@ -1028,7 +1020,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("blocked by distinctive approval policy"),
|
||||
expected_reason: None,
|
||||
@@ -1046,7 +1037,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1064,7 +1054,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApprovalWithAmendment {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1092,7 +1081,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApprovalWithAmendment {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1120,7 +1108,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::CommandFailure {
|
||||
output_contains: "you cannot ask for escalated permissions",
|
||||
@@ -1136,7 +1123,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApprovalWithAmendment {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1158,7 +1144,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1179,7 +1164,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1200,7 +1184,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApprovalWithAmendment {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1220,7 +1203,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1240,7 +1222,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1260,7 +1241,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileCreated {
|
||||
target: TargetPath::OutsideWorkspace("dfa_never.txt"),
|
||||
@@ -1277,7 +1257,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileCreatedNoExitCode {
|
||||
target: TargetPath::OutsideWorkspace("dfa_never_5_1.txt"),
|
||||
@@ -1294,7 +1273,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1314,7 +1292,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1333,7 +1310,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::CommandSuccess {
|
||||
stdout_contains: "trusted-read-only",
|
||||
@@ -1348,7 +1324,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::CommandSuccessNoExitCode {
|
||||
stdout_contains: "trusted-read-only",
|
||||
@@ -1364,7 +1339,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: None,
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::NetworkFailure { expect_tag: "ERR:" },
|
||||
},
|
||||
@@ -1378,7 +1352,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: None,
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1398,7 +1371,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1417,7 +1389,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1436,7 +1407,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: None,
|
||||
outcome: Outcome::PatchApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1456,7 +1426,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::PatchApplied {
|
||||
target: TargetPath::Workspace("apply_patch_freeform.txt"),
|
||||
@@ -1473,7 +1442,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::PatchApplied {
|
||||
target: TargetPath::OutsideWorkspace("apply_patch_freeform_danger.txt"),
|
||||
@@ -1490,7 +1458,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::PatchApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1510,7 +1477,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::PatchApproval {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1530,7 +1496,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: None,
|
||||
outcome: Outcome::PatchApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1550,7 +1515,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::PatchApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1570,7 +1534,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileNotCreated {
|
||||
target: TargetPath::OutsideWorkspace("apply_patch_freeform_never.txt"),
|
||||
@@ -1589,7 +1552,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: None,
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileNotCreated {
|
||||
target: TargetPath::Workspace("ro_never.txt"),
|
||||
@@ -1612,7 +1574,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::CommandSuccess {
|
||||
stdout_contains: "trusted-never",
|
||||
@@ -1628,7 +1589,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileCreated {
|
||||
target: TargetPath::Workspace("ww_on_request.txt"),
|
||||
@@ -1645,7 +1605,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: None,
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::NetworkFailure { expect_tag: "ERR:" },
|
||||
},
|
||||
@@ -1659,7 +1618,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: None,
|
||||
@@ -1679,7 +1637,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::NetworkSuccess {
|
||||
body_contains: "workspace-network-ok",
|
||||
@@ -1695,7 +1652,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: None,
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileNotCreated {
|
||||
target: TargetPath::OutsideWorkspace("ww_never.txt"),
|
||||
@@ -1719,7 +1675,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![Feature::UnifiedExec],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::CommandSuccess {
|
||||
stdout_contains: "hello unified exec",
|
||||
@@ -1737,7 +1692,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![Feature::UnifiedExec],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: Some(DEFAULT_UNIFIED_EXEC_JUSTIFICATION),
|
||||
@@ -1756,7 +1710,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![Feature::UnifiedExec],
|
||||
model_override: None,
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1775,7 +1728,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![Feature::UnifiedExec],
|
||||
model_override: None,
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1794,7 +1746,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::RequireEscalated,
|
||||
features: vec![Feature::UnifiedExec],
|
||||
model_override: None,
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected by user"),
|
||||
expected_reason: None,
|
||||
@@ -1814,7 +1765,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected dynamic shell word"),
|
||||
expected_reason: None,
|
||||
@@ -1832,7 +1782,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected dynamic shell word"),
|
||||
expected_reason: None,
|
||||
@@ -1851,7 +1800,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected dynamic shell word"),
|
||||
expected_reason: None,
|
||||
@@ -1870,7 +1818,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected dynamic shell word"),
|
||||
expected_reason: None,
|
||||
@@ -1888,7 +1835,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected dynamic shell word"),
|
||||
expected_reason: None,
|
||||
@@ -1906,7 +1852,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected dynamic shell word"),
|
||||
expected_reason: None,
|
||||
@@ -1924,7 +1869,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected dynamic shell word"),
|
||||
expected_reason: None,
|
||||
@@ -1943,7 +1887,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("rejected dynamic shell word"),
|
||||
expected_reason: None,
|
||||
@@ -1961,7 +1904,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::denied("blocked in untrusted project"),
|
||||
expected_reason: None,
|
||||
@@ -2027,29 +1969,27 @@ async fn run_scenario(scenario: &ScenarioSpec) -> Result<()> {
|
||||
let approval_policy = scenario.approval_policy;
|
||||
let sandbox_policy = scenario.sandbox_policy.clone();
|
||||
let features = scenario.features.clone();
|
||||
let model_override = scenario.model_override;
|
||||
let model = model_override.unwrap_or("gpt-5.4");
|
||||
let policy_src = scenario.action.policy_src();
|
||||
let thread_store_id = format!("approval-scenario-{}", scenario.name);
|
||||
let model_catalog = bundled_models_response()?;
|
||||
|
||||
let mut builder = test_codex().with_model(model).with_config(move |config| {
|
||||
config.model_catalog = Some(model_catalog);
|
||||
// These scenarios assert tool behavior, not rollout persistence.
|
||||
config.experimental_thread_store = ThreadStoreConfig::InMemory {
|
||||
id: thread_store_id,
|
||||
};
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config
|
||||
.set_legacy_sandbox_policy(sandbox_policy.clone())
|
||||
.expect("set sandbox policy");
|
||||
for feature in features {
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
// These scenarios assert tool behavior, not rollout persistence.
|
||||
config.experimental_thread_store = ThreadStoreConfig::InMemory {
|
||||
id: thread_store_id,
|
||||
};
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config
|
||||
.features
|
||||
.enable(feature)
|
||||
.expect("test config should allow feature update");
|
||||
}
|
||||
});
|
||||
.set_legacy_sandbox_policy(sandbox_policy.clone())
|
||||
.expect("set sandbox policy");
|
||||
for feature in features {
|
||||
config
|
||||
.features
|
||||
.enable(feature)
|
||||
.expect("test config should allow feature update");
|
||||
}
|
||||
});
|
||||
if let Some(policy_src) = policy_src {
|
||||
builder = builder.with_pre_build_hook(move |home| {
|
||||
let rules_dir = home.join("rules");
|
||||
|
||||
@@ -2309,7 +2309,7 @@ async fn includes_default_reasoning_effort_in_request_when_defined_by_model_info
|
||||
sse(vec![ev_response_created("resp1"), ev_completed("resp1")]),
|
||||
)
|
||||
.await;
|
||||
let TestCodex { codex, .. } = test_codex().with_model("gpt-5.4").build(&server).await?;
|
||||
let TestCodex { codex, .. } = test_codex().with_model("gpt-5.5").build(&server).await?;
|
||||
|
||||
codex
|
||||
.start_or_steer_turn(TurnInputRequest::user_input(vec![UserInput::Text {
|
||||
@@ -2463,12 +2463,12 @@ async fn model_without_summary_parameter_support_omits_configured_summary() -> a
|
||||
let model = model_catalog
|
||||
.models
|
||||
.iter_mut()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.expect("gpt-5.4 exists in bundled models.json");
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("gpt-5.5 exists in bundled models.json");
|
||||
model.supports_reasoning_summary_parameter = false;
|
||||
|
||||
let TestCodex { codex, .. } = test_codex()
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
config.model_catalog = Some(model_catalog);
|
||||
config.model_reasoning_effort = Some(ReasoningEffort::High);
|
||||
@@ -2597,8 +2597,8 @@ async fn user_turn_explicit_reasoning_summary_overrides_model_catalog_default()
|
||||
let model = model_catalog
|
||||
.models
|
||||
.iter_mut()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.expect("gpt-5.4 exists in bundled models.json");
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("gpt-5.5 exists in bundled models.json");
|
||||
model.default_reasoning_summary = ReasoningSummary::Detailed;
|
||||
|
||||
let TestCodex {
|
||||
@@ -2607,7 +2607,7 @@ async fn user_turn_explicit_reasoning_summary_overrides_model_catalog_default()
|
||||
session_configured,
|
||||
..
|
||||
} = test_codex()
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
config.model_catalog = Some(model_catalog);
|
||||
})
|
||||
@@ -2710,12 +2710,12 @@ async fn reasoning_summary_none_overrides_model_catalog_default() -> anyhow::Res
|
||||
let model = model_catalog
|
||||
.models
|
||||
.iter_mut()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.expect("gpt-5.4 exists in bundled models.json");
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("gpt-5.5 exists in bundled models.json");
|
||||
model.default_reasoning_summary = ReasoningSummary::Detailed;
|
||||
|
||||
let TestCodex { codex, .. } = test_codex()
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
config.model_reasoning_summary = Some(ReasoningSummary::None);
|
||||
config.model_catalog = Some(model_catalog);
|
||||
@@ -2754,7 +2754,7 @@ async fn includes_default_verbosity_in_request() -> anyhow::Result<()> {
|
||||
sse(vec![ev_response_created("resp1"), ev_completed("resp1")]),
|
||||
)
|
||||
.await;
|
||||
let TestCodex { codex, .. } = test_codex().with_model("gpt-5.4").build(&server).await?;
|
||||
let TestCodex { codex, .. } = test_codex().with_model("gpt-5.5").build(&server).await?;
|
||||
|
||||
codex
|
||||
.start_or_steer_turn(TurnInputRequest::user_input(vec![UserInput::Text {
|
||||
@@ -2832,7 +2832,7 @@ async fn configured_verbosity_is_sent() -> anyhow::Result<()> {
|
||||
)
|
||||
.await;
|
||||
let TestCodex { codex, .. } = test_codex()
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(|config| {
|
||||
config.model_verbosity = Some(Verbosity::High);
|
||||
})
|
||||
|
||||
@@ -1384,10 +1384,10 @@ if (!tool) {
|
||||
let model = model_catalog
|
||||
.models
|
||||
.iter_mut()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.expect("gpt-5.4 exists in bundled models.json");
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("gpt-5.5 exists in bundled models.json");
|
||||
config.chatgpt_base_url = apps_base_url;
|
||||
config.model = Some("gpt-5.4".to_string());
|
||||
config.model = Some("gpt-5.5".to_string());
|
||||
model.supports_search_tool = true;
|
||||
config.model_catalog = Some(model_catalog);
|
||||
});
|
||||
@@ -1879,7 +1879,7 @@ text(JSON.stringify([results[0].output.includes("code-alpha-ready"), results[1].
|
||||
|
||||
// This model uses token-based tool-output truncation, giving the downstream
|
||||
// history assertions a stable `…N tokens truncated…` marker.
|
||||
const TOKEN_POLICY_TEST_MODEL: &str = "gpt-5.4";
|
||||
const TOKEN_POLICY_TEST_MODEL: &str = "gpt-5.5";
|
||||
|
||||
// A nested `exec_command` limit applies to `result.output` inside JavaScript.
|
||||
// The outer code-mode and history budgets apply after the script calls `text`.
|
||||
@@ -4079,7 +4079,7 @@ async fn code_mode_resizes_explicit_original_image() -> Result<()> {
|
||||
&server,
|
||||
"use exec to return a large original-detail image",
|
||||
&code,
|
||||
"gpt-5.4",
|
||||
"gpt-5.5",
|
||||
|_| {},
|
||||
)
|
||||
.await?;
|
||||
@@ -4138,7 +4138,7 @@ image({{
|
||||
&server,
|
||||
"emit images with legacy detail arguments and MCP metadata",
|
||||
&code,
|
||||
"gpt-5.4",
|
||||
"gpt-5.5",
|
||||
|config| {
|
||||
let _ = config.features.enable(Feature::UnifiedImageBudget);
|
||||
},
|
||||
@@ -4183,14 +4183,21 @@ async fn code_mode_unified_image_budget_preserves_legacy_contract_for_unsupporte
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let (_test, second_mock) = run_code_mode_turn_with_model_and_config(
|
||||
&server,
|
||||
"emit an image on a legacy model",
|
||||
r#"image("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==");"#,
|
||||
"gpt-5.2",
|
||||
|config| {
|
||||
let builder = test_codex()
|
||||
.with_model_info_override("image-budget-unsupported-model", |model| {
|
||||
model.tool_mode = Some(ToolMode::CodeMode);
|
||||
model.supports_image_detail_original = false;
|
||||
})
|
||||
.with_config(|config| {
|
||||
let _ = config.features.enable(Feature::CodeMode);
|
||||
let _ = config.features.enable(Feature::ExecutedToolCallMetadata);
|
||||
let _ = config.features.enable(Feature::UnifiedImageBudget);
|
||||
},
|
||||
});
|
||||
let (_test, second_mock) = run_code_mode_turn_with_builder(
|
||||
&server,
|
||||
"emit an image on a model without original-detail support",
|
||||
r#"image("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==");"#,
|
||||
builder,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -4219,7 +4226,7 @@ async fn code_mode_view_image_rejects_invalid_file_without_exposing_contents() -
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let builder = test_codex()
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(|config| {
|
||||
let _ = config.features.enable(Feature::CodeMode);
|
||||
})
|
||||
@@ -4268,7 +4275,7 @@ async fn code_mode_can_use_view_image_result_with_image_helper(
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
let _ = config.features.enable(Feature::CodeMode);
|
||||
if unified_image_budget {
|
||||
@@ -4404,7 +4411,7 @@ image(imageItem);
|
||||
&server,
|
||||
"use exec to call the rmcp image scenario tool and emit its image output",
|
||||
code,
|
||||
"gpt-5.4",
|
||||
"gpt-5.5",
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -407,9 +407,12 @@ fn model_info_with_context_window(slug: &str, context_window: i64) -> ModelInfo
|
||||
let mut model_info = models_response
|
||||
.models
|
||||
.into_iter()
|
||||
.find(|model| model.slug == slug)
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("model missing from models.json");
|
||||
model_info.slug = slug.to_string();
|
||||
model_info.context_window = Some(context_window);
|
||||
model_info.max_context_window = Some(context_window);
|
||||
model_info.comp_hash = None;
|
||||
model_info
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,15 @@ fn test_model_info(
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_model_switching_fixture(model: &mut ModelInfo) {
|
||||
// Exercise model selection and history without changing the request transport,
|
||||
// starting Code Mode, or compacting the mocked history on a model switch.
|
||||
model.tool_mode = None;
|
||||
model.multi_agent_version = None;
|
||||
model.use_responses_lite = false;
|
||||
model.comp_hash = None;
|
||||
}
|
||||
|
||||
#[test_case(None; "model only")]
|
||||
#[test_case(Some(Personality::Pragmatic); "model and personality")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
@@ -177,14 +186,16 @@ async fn first_turn_model_change_appends_model_instructions_developer_message(
|
||||
let server = MockServer::start().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
|
||||
let mut builder = test_codex().with_model("gpt-5.2").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let mut builder = test_codex()
|
||||
.with_model_info_override("gpt-5.6-terra", configure_model_switching_fixture)
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
let next_model = "gpt-5.4";
|
||||
let next_model = "gpt-5.5";
|
||||
|
||||
submit_model_turn(
|
||||
&test.codex,
|
||||
@@ -220,10 +231,10 @@ async fn first_turn_model_change_appends_model_instructions_developer_message(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(None, "gpt-5.2"; "model-generated base instructions and original model")]
|
||||
#[test_case(None, "gpt-5.4"; "model-generated base instructions and fork model")]
|
||||
#[test_case(Some("inherited custom base instructions"), "gpt-5.2"; "custom base instructions and original model")]
|
||||
#[test_case(Some("inherited custom base instructions"), "gpt-5.4"; "custom base instructions and fork model")]
|
||||
#[test_case(None, "gpt-5.6-terra"; "model-generated base instructions and original model")]
|
||||
#[test_case(None, "gpt-5.5"; "model-generated base instructions and fork model")]
|
||||
#[test_case(Some("inherited custom base instructions"), "gpt-5.6-terra"; "custom base instructions and original model")]
|
||||
#[test_case(Some("inherited custom base instructions"), "gpt-5.5"; "custom base instructions and fork model")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn first_turn_after_empty_prefix_fork_preserves_inherited_base_instructions(
|
||||
custom_base_instructions: Option<&'static str>,
|
||||
@@ -234,9 +245,9 @@ async fn first_turn_after_empty_prefix_fork_preserves_inherited_base_instruction
|
||||
let server = MockServer::start().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-fork")).await;
|
||||
|
||||
let initial_model = "gpt-5.2";
|
||||
let initial_model = "gpt-5.6-terra";
|
||||
let mut builder = test_codex()
|
||||
.with_model(initial_model)
|
||||
.with_model_info_override(initial_model, configure_model_switching_fixture)
|
||||
.with_config(move |config| {
|
||||
config.base_instructions = custom_base_instructions.map(str::to_string);
|
||||
});
|
||||
@@ -260,7 +271,7 @@ async fn first_turn_after_empty_prefix_fork_preserves_inherited_base_instruction
|
||||
);
|
||||
|
||||
let mut fork_config = test.config.clone();
|
||||
fork_config.model = Some("gpt-5.4".to_string());
|
||||
fork_config.model = Some("gpt-5.5".to_string());
|
||||
fork_config.base_instructions = None;
|
||||
let fork = test
|
||||
.thread_manager
|
||||
@@ -337,13 +348,13 @@ async fn rollback_first_turn_model_change_removes_its_instructions(
|
||||
)
|
||||
.await;
|
||||
|
||||
let initial_model = "gpt-5.2";
|
||||
let switched_model = "gpt-5.4";
|
||||
let initial_model = "gpt-5.6-terra";
|
||||
let switched_model = "gpt-5.5";
|
||||
let rollback_ready = Arc::new(RollbackReady::default());
|
||||
let mut extensions = ExtensionRegistryBuilder::new();
|
||||
extensions.thread_lifecycle_contributor(rollback_ready.clone());
|
||||
let mut builder = test_codex()
|
||||
.with_model(initial_model)
|
||||
.with_model_info_override(initial_model, configure_model_switching_fixture)
|
||||
.with_extensions(Arc::new(extensions.build()));
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
|
||||
@@ -368,7 +379,9 @@ async fn rollback_first_turn_model_change_removes_its_instructions(
|
||||
|
||||
let test = match followup {
|
||||
RollbackFollowup::ColdResume => {
|
||||
let mut resume_builder = test_codex().with_model(switched_model);
|
||||
let mut resume_builder = test_codex()
|
||||
.with_model_info_override(initial_model, configure_model_switching_fixture)
|
||||
.with_model(switched_model);
|
||||
resume_builder.restart(&server, &test).await?
|
||||
}
|
||||
RollbackFollowup::StartupModel | RollbackFollowup::SwitchedModel => test,
|
||||
@@ -425,9 +438,10 @@ async fn model_change_appends_model_instructions_developer_message() -> Result<(
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex().with_model("gpt-5.2");
|
||||
let mut builder =
|
||||
test_codex().with_model_info_override("gpt-5.6-terra", configure_model_switching_fixture);
|
||||
let test = builder.build(&server).await?;
|
||||
let next_model = "gpt-5.4";
|
||||
let next_model = "gpt-5.5";
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_user_turn(
|
||||
@@ -516,7 +530,7 @@ async fn model_and_personality_change_only_appends_model_instructions() -> Resul
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
@@ -624,16 +638,18 @@ async fn settings_update_during_active_turn_applies_to_next_turn_only() -> Resul
|
||||
],
|
||||
)
|
||||
.await;
|
||||
let mut builder = test_codex().with_model("gpt-5.2").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::DefaultModeRequestUserInput)
|
||||
.expect("test config should allow feature update");
|
||||
config.model_reasoning_effort = Some(ReasoningEffort::Low);
|
||||
config.model_reasoning_summary = Some(ReasoningSummary::Concise);
|
||||
config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest);
|
||||
config.approvals_reviewer = ApprovalsReviewer::User;
|
||||
});
|
||||
let mut builder = test_codex()
|
||||
.with_model_info_override("gpt-5.6-terra", configure_model_switching_fixture)
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::DefaultModeRequestUserInput)
|
||||
.expect("test config should allow feature update");
|
||||
config.model_reasoning_effort = Some(ReasoningEffort::Low);
|
||||
config.model_reasoning_summary = Some(ReasoningSummary::Concise);
|
||||
config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest);
|
||||
config.approvals_reviewer = ApprovalsReviewer::User;
|
||||
});
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
|
||||
test.codex
|
||||
@@ -651,7 +667,7 @@ async fn settings_update_during_active_turn_applies_to_next_turn_only() -> Resul
|
||||
core_test_support::submit_thread_settings(
|
||||
&test.codex,
|
||||
ThreadSettingsOverrides {
|
||||
model: Some("gpt-5.4".to_string()),
|
||||
model: Some("gpt-5.5".to_string()),
|
||||
effort: Some(Some(ReasoningEffort::High)),
|
||||
summary: Some(ReasoningSummary::Detailed),
|
||||
service_tier: Some(Some(ServiceTier::Fast.request_value().to_string())),
|
||||
@@ -701,19 +717,19 @@ async fn settings_update_during_active_turn_applies_to_next_turn_only() -> Resul
|
||||
request_settings,
|
||||
vec![
|
||||
json!({
|
||||
"model": "gpt-5.2",
|
||||
"model": "gpt-5.6-terra",
|
||||
"reasoning": { "effort": "low", "summary": "concise" },
|
||||
"service_tier": null,
|
||||
"approval_policy_never": false,
|
||||
}),
|
||||
json!({
|
||||
"model": "gpt-5.2",
|
||||
"model": "gpt-5.6-terra",
|
||||
"reasoning": { "effort": "low", "summary": "concise" },
|
||||
"service_tier": null,
|
||||
"approval_policy_never": false,
|
||||
}),
|
||||
json!({
|
||||
"model": "gpt-5.4",
|
||||
"model": "gpt-5.5",
|
||||
"reasoning": { "effort": "high", "summary": "detailed" },
|
||||
"service_tier": "priority",
|
||||
"approval_policy_never": true,
|
||||
|
||||
@@ -514,7 +514,7 @@ async fn snapshot_model_visible_layout_resume_with_personality_change() -> Resul
|
||||
.with_extensions(skills_extensions())
|
||||
.with_config(|config| {
|
||||
config.update_plan_enabled = true;
|
||||
config.model = Some("gpt-5.2".to_string());
|
||||
config.model = Some("gpt-5.5".to_string());
|
||||
});
|
||||
let initial = initial_builder.build(&server).await?;
|
||||
let codex = Arc::clone(&initial.codex);
|
||||
|
||||
@@ -26,7 +26,7 @@ async fn auth_and_provider_switches_do_not_reuse_chatgpt_catalog() -> Result<()>
|
||||
let mut model = bundled_models_response()?
|
||||
.models
|
||||
.into_iter()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.unwrap();
|
||||
model.visibility = ModelVisibility::List;
|
||||
model.default_service_tier = Some("priority".into());
|
||||
@@ -40,7 +40,7 @@ async fn auth_and_provider_switches_do_not_reuse_chatgpt_catalog() -> Result<()>
|
||||
let chatgpt = test_codex()
|
||||
.with_home(home.clone())
|
||||
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.build_with_auto_env(&server)
|
||||
.await?;
|
||||
assert!(home.path().join("models_cache.json").exists());
|
||||
@@ -77,7 +77,7 @@ async fn auth_and_provider_switches_do_not_reuse_chatgpt_catalog() -> Result<()>
|
||||
let api = test_codex()
|
||||
.with_home(home.clone())
|
||||
.with_auth(CodexAuth::from_api_key("api-key"))
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.build_with_auto_env(&server)
|
||||
.await?;
|
||||
let ordinary = responses::mount_sse_once(
|
||||
@@ -124,7 +124,7 @@ async fn auth_and_provider_switches_do_not_reuse_chatgpt_catalog() -> Result<()>
|
||||
let other = test_codex()
|
||||
.with_home(home)
|
||||
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(|config| {
|
||||
config.model_provider_id = "second".into();
|
||||
config.model_provider.name = "Second".into();
|
||||
|
||||
@@ -44,6 +44,7 @@ use wiremock::MockServer;
|
||||
|
||||
const LOCAL_FRIENDLY_TEMPLATE: &str =
|
||||
"You optimize for team morale and being a supportive teammate as much as code quality.";
|
||||
const BUNDLED_FRIENDLY_TEMPLATE: &str = "You have a vivid inner life as Codex:";
|
||||
const LOCAL_PRAGMATIC_TEMPLATE: &str = "You are a deeply pragmatic, effective software engineer.";
|
||||
|
||||
fn read_only_text_turn(
|
||||
@@ -93,7 +94,7 @@ async fn user_turn_personality_none_does_not_add_update_message() -> anyhow::Res
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
@@ -130,7 +131,7 @@ async fn config_personality_some_sets_instructions_template() -> anyhow::Result<
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
@@ -154,7 +155,7 @@ async fn config_personality_some_sets_instructions_template() -> anyhow::Result<
|
||||
let instructions_text = request.instructions_text();
|
||||
|
||||
assert!(
|
||||
instructions_text.contains(LOCAL_FRIENDLY_TEMPLATE),
|
||||
instructions_text.contains(BUNDLED_FRIENDLY_TEMPLATE),
|
||||
"expected personality update to include the local friendly template, got: {instructions_text:?}"
|
||||
);
|
||||
|
||||
@@ -175,7 +176,7 @@ async fn config_personality_none_sends_no_personality() -> anyhow::Result<()> {
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
@@ -198,7 +199,7 @@ async fn config_personality_none_sends_no_personality() -> anyhow::Result<()> {
|
||||
let request = resp_mock.single_request();
|
||||
let instructions_text = request.instructions_text();
|
||||
assert!(
|
||||
!instructions_text.contains(LOCAL_FRIENDLY_TEMPLATE),
|
||||
!instructions_text.contains(BUNDLED_FRIENDLY_TEMPLATE),
|
||||
"expected no friendly personality template, got: {instructions_text:?}"
|
||||
);
|
||||
assert!(
|
||||
@@ -228,7 +229,7 @@ async fn config_personality_none_strips_baked_personality_section() -> anyhow::R
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex()
|
||||
.with_model_info_override("gpt-5.4", |model_info| {
|
||||
.with_model_info_override("gpt-5.5", |model_info| {
|
||||
if let Some(model_messages) = model_info.model_messages.as_mut() {
|
||||
model_messages.instructions_template = Some("Base instructions\n# Personality\nBaked personality\n## Writing Style\nNested writing style\n# General\nGeneral instructions".to_string());
|
||||
model_messages.instructions_variables = None;
|
||||
@@ -270,7 +271,7 @@ async fn config_personality_none_preserves_explicit_base_instructions() -> anyho
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
@@ -305,7 +306,7 @@ async fn default_personality_is_pragmatic_without_config_toml() -> anyhow::Resul
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex().with_model("gpt-5.4").with_config(|config| {
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
@@ -490,8 +491,8 @@ async fn disabled_personality_sends_remote_default_instructions() -> anyhow::Res
|
||||
let mut remote_model = bundled_models_response()?
|
||||
.models
|
||||
.into_iter()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.expect("bundled gpt-5.4 model");
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("bundled gpt-5.5 model");
|
||||
remote_model.slug = remote_slug.to_string();
|
||||
if let Some(model_messages) = remote_model.model_messages.as_mut() {
|
||||
model_messages.instructions_template = Some("remote base\n{{ personality }}".to_string());
|
||||
@@ -837,7 +838,7 @@ async fn user_turn_personality_remote_model_template_includes_update_message() -
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.model = Some("gpt-5.4".to_string());
|
||||
config.model = Some("gpt-5.5".to_string());
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
|
||||
@@ -2,17 +2,21 @@
|
||||
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use codex_core::TurnInputRequest;
|
||||
use codex_core::shell::default_user_shell;
|
||||
use codex_features::Feature;
|
||||
use codex_models_manager::bundled_models_response;
|
||||
use codex_models_manager::collaboration_mode_presets::builtin_collaboration_mode_presets;
|
||||
use codex_models_manager::manager::StaticModelsManager;
|
||||
use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::ReasoningSummary;
|
||||
use codex_protocol::config_types::Settings;
|
||||
use codex_protocol::config_types::WebSearchMode;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::openai_models::ModelsResponse;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
@@ -135,6 +139,25 @@ async fn prompt_tools_are_consistent_across_requests(
|
||||
|
||||
const CUSTOM_BASE_INSTRUCTIONS: &str =
|
||||
"Custom base.\r\n## Plan tool\r\nPreserve this custom workflow.\r\n";
|
||||
const MODEL_BASE_INSTRUCTIONS: &str = "Model base.\n\n## Planning\nYou have access to an `update_plan` tool which tracks steps.\n\n## Work\nKeep working.\n\n## `update_plan`\nUpdate the plan.\n";
|
||||
|
||||
let mut model = bundled_models_response()?
|
||||
.models
|
||||
.into_iter()
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("bundled gpt-5.5 model");
|
||||
model
|
||||
.model_messages
|
||||
.as_mut()
|
||||
.expect("bundled model messages")
|
||||
.instructions_template = Some(MODEL_BASE_INSTRUCTIONS.to_string());
|
||||
// Supply model instructions without making them an explicit config catalog override.
|
||||
let models_manager = Arc::new(StaticModelsManager::new(
|
||||
/*auth_manager*/ None,
|
||||
ModelsResponse {
|
||||
models: vec![model],
|
||||
},
|
||||
));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let req1 = mount_sse_once(
|
||||
@@ -154,9 +177,10 @@ async fn prompt_tools_are_consistent_across_requests(
|
||||
thread_manager,
|
||||
..
|
||||
} = test_codex()
|
||||
.with_models_manager(models_manager)
|
||||
.with_pre_build_hook(write_global_instructions)
|
||||
.with_config(move |config| {
|
||||
config.model = Some("gpt-5.2".to_string());
|
||||
config.model = Some("gpt-5.5".to_string());
|
||||
if let Some(update_plan_enabled) = update_plan_enabled {
|
||||
config.update_plan_enabled = update_plan_enabled;
|
||||
}
|
||||
@@ -220,7 +244,7 @@ async fn prompt_tools_are_consistent_across_requests(
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
mode: ModeKind::Plan,
|
||||
settings: Settings {
|
||||
model: "gpt-5.2".to_string(),
|
||||
model: "gpt-5.5".to_string(),
|
||||
reasoning_effort: None,
|
||||
developer_instructions: Some(mode_instructions.clone()),
|
||||
},
|
||||
|
||||
@@ -76,8 +76,8 @@ async fn disabled_update_plan_preserves_custom_catalog_instructions() -> Result<
|
||||
let model = catalog
|
||||
.models
|
||||
.iter_mut()
|
||||
.find(|model| model.slug == "gpt-5.2")
|
||||
.expect("bundled gpt-5.2 model");
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("bundled gpt-5.5 model");
|
||||
let messages = model
|
||||
.model_messages
|
||||
.as_mut()
|
||||
@@ -85,7 +85,7 @@ async fn disabled_update_plan_preserves_custom_catalog_instructions() -> Result<
|
||||
messages.instructions_template = Some(INSTRUCTIONS.to_string());
|
||||
messages.instructions_variables = None;
|
||||
let test = test_codex()
|
||||
.with_model("gpt-5.2")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
config.update_plan_enabled = false;
|
||||
config.model_catalog = Some(catalog);
|
||||
@@ -544,7 +544,7 @@ async fn namespaced_model_slug_uses_catalog_metadata_without_fallback_warning()
|
||||
skip_if_sandbox!(Ok(()));
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let requested_model = "custom/gpt-5.2-codex";
|
||||
let requested_model = "custom/gpt-5.5-codex";
|
||||
let response_mock = mount_sse_once(
|
||||
&server,
|
||||
sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]),
|
||||
|
||||
@@ -137,10 +137,10 @@ fn configure_apps_without_search_tool(config: &mut Config, apps_base_url: &str)
|
||||
let model = model_catalog
|
||||
.models
|
||||
.iter_mut()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.expect("gpt-5.4 exists in bundled models.json");
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("gpt-5.5 exists in bundled models.json");
|
||||
config.chatgpt_base_url = apps_base_url.to_string();
|
||||
config.model = Some("gpt-5.4".to_string());
|
||||
config.model = Some("gpt-5.5".to_string());
|
||||
config.tool_suggest.discoverables = vec![ToolSuggestDiscoverable {
|
||||
kind: ToolSuggestDiscoverableType::Connector,
|
||||
id: DISCOVERABLE_GMAIL_ID.to_string(),
|
||||
@@ -1059,7 +1059,7 @@ async fn run_remote_plugin_install_metadata_case() -> Result<()> {
|
||||
"source": "endpoint_recommendation",
|
||||
"thread_id": thread_id,
|
||||
"turn_id": turn_id,
|
||||
"model_slug": "gpt-5.4",
|
||||
"model_slug": "gpt-5.5",
|
||||
"product_client_id": codex_login::default_client::originator().value,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1749,7 +1749,7 @@ async fn stdio_mcp_tool_call_includes_sandbox_state_meta(
|
||||
let model = models
|
||||
.models
|
||||
.iter_mut()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("bundled model should exist");
|
||||
model.node_repl_auto_review_required = node_repl_auto_review_required;
|
||||
model.node_repl_disabled = node_repl_disabled;
|
||||
@@ -1803,7 +1803,7 @@ async fn stdio_mcp_tool_call_includes_sandbox_state_meta(
|
||||
let rmcp_test_server_bin = remote_aware_stdio_server_bin()?;
|
||||
let fixture = test_codex()
|
||||
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_model("gpt-5.4")
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
insert_mcp_server(
|
||||
config,
|
||||
|
||||
@@ -310,7 +310,7 @@ async fn model_verification_emits_structured_event_without_reroute_or_warning()
|
||||
]));
|
||||
let _mock = mount_response_once(&server, response).await;
|
||||
|
||||
let mut builder = test_codex().with_model(SERVER_MODEL);
|
||||
let mut builder = test_codex().with_model("gpt-5.5");
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
|
||||
@@ -702,7 +702,7 @@ async fn tool_search_returns_deferred_tools_without_follow_up_tool_injection() -
|
||||
apps_tool_call
|
||||
.pointer("/params/_meta/x-codex-turn-metadata/model")
|
||||
.and_then(Value::as_str),
|
||||
Some("gpt-5.4")
|
||||
Some("gpt-5.5")
|
||||
);
|
||||
let first_request_reasoning_effort = first_request_body
|
||||
.pointer("/reasoning/effort")
|
||||
|
||||
@@ -121,8 +121,8 @@ fn step_settings_models() -> Vec<ModelInfo> {
|
||||
.expect("bundled models should parse")
|
||||
.models
|
||||
.into_iter()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.expect("bundled gpt-5.4 model");
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("bundled gpt-5.5 model");
|
||||
[MODEL_A, MODEL_B, MODEL_C]
|
||||
.into_iter()
|
||||
.map(|slug| {
|
||||
|
||||
@@ -66,7 +66,7 @@ async fn ordinary_settings_updates_keep_the_running_turn_snapshot() -> Result<()
|
||||
.unwrap()
|
||||
.models
|
||||
.into_iter()
|
||||
.find(|model| model.slug == "gpt-5.4")
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.unwrap();
|
||||
config.model_catalog = Some(ModelsResponse {
|
||||
models: ["snapshot-model-a", "snapshot-model-b"]
|
||||
|
||||
@@ -79,15 +79,15 @@ const TURN_0_FORK_PROMPT: &str = "seed fork context";
|
||||
const TURN_1_PROMPT: &str = "spawn a child and continue";
|
||||
const TURN_2_NO_WAIT_PROMPT: &str = "follow up without wait";
|
||||
const CHILD_PROMPT: &str = "child: do work";
|
||||
const INHERITED_MODEL: &str = "gpt-5.2";
|
||||
const INHERITED_MODEL: &str = "gpt-5.5";
|
||||
const INHERITED_REASONING_EFFORT: ReasoningEffort = ReasoningEffort::XHigh;
|
||||
const REQUESTED_MODEL: &str = "gpt-5.4";
|
||||
const REQUESTED_MODEL: &str = "gpt-5.6-luna";
|
||||
const REQUESTED_REASONING_EFFORT: ReasoningEffort = ReasoningEffort::Low;
|
||||
const V2_DEFAULT_MODEL: &str = "gpt-5.6-terra";
|
||||
const V2_DEFAULT_REASONING_EFFORT: ReasoningEffort = ReasoningEffort::High;
|
||||
const V2_REQUESTED_MODEL: &str = "gpt-5.6-sol";
|
||||
const V2_REQUESTED_REASONING_EFFORT: ReasoningEffort = ReasoningEffort::Low;
|
||||
const ROLE_MODEL: &str = "gpt-5.4";
|
||||
const ROLE_MODEL: &str = "gpt-5.5";
|
||||
const ROLE_REASONING_EFFORT: ReasoningEffort = ReasoningEffort::High;
|
||||
const SUBAGENT_START_CONTEXT: &str = "subagent start context reaches child";
|
||||
const SUBAGENT_STOP_CONTINUATION: &str = "continue only the child";
|
||||
@@ -1024,6 +1024,7 @@ async fn spawned_child_receives_forked_parent_context(
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_model_info_override(INHERITED_MODEL, |model| model.comp_hash = None)
|
||||
.with_history_mode(history_mode)
|
||||
.with_config(|config| {
|
||||
config
|
||||
@@ -1522,6 +1523,9 @@ async fn spawned_full_history_v2_child_uses_model_precedence_without_dropping_co
|
||||
.iter_mut()
|
||||
.find(|model_info| model_info.slug == model)
|
||||
.unwrap_or_else(|| panic!("{model} should exist in bundled models.json"));
|
||||
if model == INHERITED_MODEL {
|
||||
model_info.comp_hash = None;
|
||||
}
|
||||
let multi_agent = model_info
|
||||
.model_messages
|
||||
.as_mut()
|
||||
@@ -2010,9 +2014,9 @@ async fn spawned_agent_uses_summary_support_for_final_model(
|
||||
};
|
||||
assert_eq!(child_body["model"], json!(REQUESTED_MODEL));
|
||||
let expected_reasoning = if child_supports_summary {
|
||||
json!({"effort": "medium", "summary": "detailed"})
|
||||
json!({"effort": "medium", "summary": "detailed", "context": "all_turns"})
|
||||
} else {
|
||||
json!({"effort": "medium"})
|
||||
json!({"effort": "medium", "context": "all_turns"})
|
||||
};
|
||||
assert_eq!(child_body["reasoning"], expected_reasoning);
|
||||
assert_eq!(
|
||||
@@ -3178,7 +3182,7 @@ async fn spawn_agent_rejects_reasoning_effort_unsupported_by_role_model() -> Res
|
||||
assert_eq!(
|
||||
output.as_deref(),
|
||||
Some(
|
||||
"Reasoning effort `ultra` is not supported for model `gpt-5.4`. Supported reasoning efforts: low, medium, high, xhigh"
|
||||
"Reasoning effort `ultra` is not supported for model `gpt-5.5`. Supported reasoning efforts: low, medium, high, xhigh"
|
||||
)
|
||||
);
|
||||
Ok(())
|
||||
@@ -3251,7 +3255,7 @@ async fn spawn_agent_tool_description_mentions_role_locked_settings() -> Result<
|
||||
role_block(&agent_type_description, "custom").expect("custom role description");
|
||||
assert_eq!(
|
||||
custom_role_description,
|
||||
"custom: {\nCustom role\n- This role's model is set to `gpt-5.4` and its reasoning effort is set to `high`. These settings cannot be changed.\n}"
|
||||
"custom: {\nCustom role\n- This role's model is set to `gpt-5.5` and its reasoning effort is set to `high`. These settings cannot be changed.\n}"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in new issue
Block a user