mirror of
https://github.com/openai/codex.git
synced 2026-10-19 16:17:49 +00:00
Embed friendly instructions in bundled GPT-5.4 and GPT-5.5 (#44930)
## What changed Replace the selectable personality templates in the bundled `gpt-5.4` and `gpt-5.5` definitions with fixed friendly instructions. Personality selection becomes unavailable for these models in the TUI, and submitted turns omit the personality override. Remove personality overrides from Python SDK examples and the walkthrough notebook. ## Testing Update core and TUI tests to cover fixed friendly instructions, ignored pragmatic updates, unavailable personality selection, and omitted turn overrides. Preserve coverage for selectable personalities in legacy catalogs, and add coverage for resumed legacy sessions and explicit empty instruction overrides. GitOrigin-RevId: 869a71445584272405fcbd1325efc31c224808c8
This commit is contained in:
@@ -6086,7 +6086,7 @@ async fn thread_resume_accepts_personality_override() -> Result<()> {
|
||||
|
||||
let start_id = primary
|
||||
.send_thread_start_request_with_auto_env(ThreadStartParams {
|
||||
model: Some("gpt-5.4".to_string()),
|
||||
model: Some("exp-codex-personality".to_string()),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
@@ -6124,7 +6124,7 @@ async fn thread_resume_accepts_personality_override() -> Result<()> {
|
||||
let resume_id = secondary
|
||||
.send_thread_resume_request(ThreadResumeParams {
|
||||
thread_id: thread.id,
|
||||
model: Some("gpt-5.4".to_string()),
|
||||
model: Some("exp-codex-personality".to_string()),
|
||||
personality: Some(Personality::Friendly),
|
||||
..Default::default()
|
||||
})
|
||||
|
||||
@@ -286,11 +286,6 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> {
|
||||
.with_model("gpt-5.4")
|
||||
.with_config(|config| {
|
||||
config.update_plan_enabled = true;
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::Pragmatic);
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
let preturn_context_diff_cwd = test.cwd_path().join(PRETURN_CONTEXT_DIFF_CWD);
|
||||
@@ -343,7 +338,6 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> {
|
||||
approval_policy: Some(AskForApproval::OnRequest),
|
||||
sandbox_policy: Some(second_sandbox_policy),
|
||||
permission_profile: second_permission_profile,
|
||||
personality: Some(Personality::Friendly),
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
mode: ModeKind::Default,
|
||||
settings: Settings {
|
||||
@@ -366,7 +360,7 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> {
|
||||
insta::assert_snapshot!(
|
||||
"model_visible_layout_turn_overrides",
|
||||
format_labeled_requests_snapshot(
|
||||
"Second turn changes cwd, approval policy, and personality while keeping model constant.",
|
||||
"Second turn changes cwd and approval policy while keeping model constant.",
|
||||
&[
|
||||
("First Request (Baseline)", &requests[0]),
|
||||
("Second Request (Turn Overrides)", &requests[1]),
|
||||
|
||||
@@ -7,19 +7,12 @@ use codex_models_manager::manager::SharedModelsManager;
|
||||
use codex_models_manager::model_info::BASE_INSTRUCTIONS;
|
||||
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::models::BaseInstructionsProvenance;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::openai_models::ConfigShellToolType;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
use codex_protocol::openai_models::ModelInstructionsVariables;
|
||||
use codex_protocol::openai_models::ModelMessages;
|
||||
use codex_protocol::openai_models::ModelVisibility;
|
||||
use codex_protocol::openai_models::ModelsResponse;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::openai_models::ReasoningEffortPreset;
|
||||
use codex_protocol::openai_models::TruncationPolicyConfig;
|
||||
use codex_protocol::openai_models::default_input_modalities;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::ThreadSettingsOverrides;
|
||||
@@ -36,15 +29,16 @@ use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
use pretty_assertions::assert_eq;
|
||||
use test_case::test_case;
|
||||
use tokio::time::Duration;
|
||||
use tokio::time::Instant;
|
||||
use tokio::time::sleep;
|
||||
use wiremock::BodyPrintLimit;
|
||||
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 CUSTOM_INSTRUCTIONS: &str = "Custom instructions\n# Personality\nThis must remain\n## Writing Style\nThis must also remain\n# General\nGeneral instructions";
|
||||
const LOCAL_PRAGMATIC_TEMPLATE: &str = "You are a deeply pragmatic, effective software engineer.";
|
||||
|
||||
fn read_only_text_turn(
|
||||
@@ -52,17 +46,6 @@ fn read_only_text_turn(
|
||||
text: &str,
|
||||
model: String,
|
||||
approval_policy: AskForApproval,
|
||||
) -> TurnInputRequest {
|
||||
let personality = None;
|
||||
read_only_text_turn_with_personality(test, text, model, approval_policy, personality)
|
||||
}
|
||||
|
||||
fn read_only_text_turn_with_personality(
|
||||
test: &TestCodex,
|
||||
text: &str,
|
||||
model: String,
|
||||
approval_policy: AskForApproval,
|
||||
personality: Option<Personality>,
|
||||
) -> TurnInputRequest {
|
||||
let (sandbox_policy, permission_profile) =
|
||||
turn_permission_fields(PermissionProfile::read_only(), test.cwd_path());
|
||||
@@ -75,7 +58,6 @@ fn read_only_text_turn_with_personality(
|
||||
approval_policy: Some(approval_policy),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
personality,
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
mode: ModeKind::Default,
|
||||
settings: Settings {
|
||||
@@ -88,88 +70,6 @@ fn read_only_text_turn_with_personality(
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn user_turn_personality_none_does_not_add_update_message() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
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.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn(
|
||||
&test,
|
||||
"hello",
|
||||
test.session_configured.model.clone(),
|
||||
test.config.permissions.approval_policy.value(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
let request = resp_mock.single_request();
|
||||
let developer_texts = request.message_input_texts("developer");
|
||||
assert!(
|
||||
!developer_texts
|
||||
.iter()
|
||||
.any(|text| text.contains("<personality_spec>")),
|
||||
"did not expect a personality update message when personality is None"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn config_personality_some_sets_instructions_template() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
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.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::Friendly);
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn(
|
||||
&test,
|
||||
"hello",
|
||||
test.session_configured.model.clone(),
|
||||
test.config.permissions.approval_policy.value(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
let request = resp_mock.single_request();
|
||||
let instructions_text = request.instructions_text();
|
||||
|
||||
assert!(
|
||||
instructions_text.contains(BUNDLED_FRIENDLY_TEMPLATE),
|
||||
"expected personality update to include the local friendly template, got: {instructions_text:?}"
|
||||
);
|
||||
|
||||
let developer_texts = request.message_input_texts("developer");
|
||||
for text in developer_texts {
|
||||
assert!(
|
||||
!text.contains("<personality_spec>"),
|
||||
"expected no personality update message in developer input"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn config_personality_none_sends_no_personality() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
@@ -263,23 +163,28 @@ async fn config_personality_none_strips_baked_personality_section() -> anyhow::R
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(CUSTOM_INSTRUCTIONS, true; "custom instructions")]
|
||||
#[test_case("", false; "bridge barebones")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn config_personality_none_preserves_explicit_base_instructions() -> anyhow::Result<()> {
|
||||
async fn config_personality_none_preserves_explicit_base_instructions(
|
||||
custom_instructions: &'static str,
|
||||
personality_enabled: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
const CUSTOM_INSTRUCTIONS: &str = "Custom instructions\n# Personality\nThis must remain\n## Writing Style\nThis must also remain\n# General\nGeneral instructions";
|
||||
|
||||
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.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::None);
|
||||
config.base_instructions = Some(CUSTOM_INSTRUCTIONS.to_string());
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
config
|
||||
.features
|
||||
.set_enabled(Feature::Personality, personality_enabled)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::None);
|
||||
config.base_instructions = Some(custom_instructions.to_string());
|
||||
});
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn(
|
||||
@@ -292,16 +197,19 @@ async fn config_personality_none_preserves_explicit_base_instructions() -> anyho
|
||||
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
assert_eq!(
|
||||
resp_mock.single_request().instructions_text(),
|
||||
CUSTOM_INSTRUCTIONS
|
||||
);
|
||||
let request = resp_mock.single_request();
|
||||
let body = request.body_json();
|
||||
// Responses requests omit the instructions field for an explicit empty override.
|
||||
let expected_instructions = (!custom_instructions.is_empty())
|
||||
.then(|| serde_json::Value::String(custom_instructions.to_string()));
|
||||
assert_eq!(body.get("instructions"), expected_instructions.as_ref());
|
||||
assert!(!request.body_contains_text(BUNDLED_FRIENDLY_TEMPLATE));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn default_personality_is_pragmatic_without_config_toml() -> anyhow::Result<()> {
|
||||
async fn default_instructions_are_friendly_without_config_toml() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
@@ -328,84 +236,10 @@ async fn default_personality_is_pragmatic_without_config_toml() -> anyhow::Resul
|
||||
let request = resp_mock.single_request();
|
||||
let instructions_text = request.instructions_text();
|
||||
assert!(
|
||||
instructions_text.contains(LOCAL_PRAGMATIC_TEMPLATE),
|
||||
instructions_text.contains(BUNDLED_FRIENDLY_TEMPLATE),
|
||||
"expected default friendly template, got: {instructions_text:?}"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn user_turn_personality_some_adds_update_message() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_sequence(
|
||||
&server,
|
||||
vec![sse_completed("resp-1"), sse_completed("resp-2")],
|
||||
)
|
||||
.await;
|
||||
let mut builder = test_codex()
|
||||
.with_model("exp-codex-personality")
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn(
|
||||
&test,
|
||||
"hello",
|
||||
test.session_configured.model.clone(),
|
||||
test.config.permissions.approval_policy.value(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
core_test_support::submit_thread_settings(
|
||||
&test.codex,
|
||||
ThreadSettingsOverrides {
|
||||
personality: Some(Personality::Friendly),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn(
|
||||
&test,
|
||||
"hello",
|
||||
test.session_configured.model.clone(),
|
||||
test.config.permissions.approval_policy.value(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
let requests = resp_mock.requests();
|
||||
assert_eq!(requests.len(), 2, "expected two requests");
|
||||
let request = requests
|
||||
.last()
|
||||
.expect("expected personality update request");
|
||||
|
||||
let developer_texts = request.message_input_texts("developer");
|
||||
let personality_text = developer_texts
|
||||
.iter()
|
||||
.find(|text| text.contains("<personality_spec>"))
|
||||
.expect("expected personality update message in developer input");
|
||||
|
||||
assert!(
|
||||
personality_text.contains("The user has requested a new communication style."),
|
||||
"expected personality update preamble, got {personality_text:?}"
|
||||
);
|
||||
assert!(
|
||||
personality_text.contains(LOCAL_FRIENDLY_TEMPLATE),
|
||||
"expected personality update to include the local pragmatic template, got: {personality_text:?}"
|
||||
);
|
||||
assert!(!request.body_contains_text("<personality_spec>"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -606,297 +440,175 @@ async fn user_turn_personality_skips_if_feature_disabled() -> anyhow::Result<()>
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn remote_model_friendly_personality_instructions_with_feature() -> anyhow::Result<()> {
|
||||
async fn legacy_remote_catalog_renders_selection_and_updates() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = MockServer::builder()
|
||||
.body_print_limit(BodyPrintLimit::Limited(80_000))
|
||||
.start()
|
||||
.await;
|
||||
|
||||
let remote_slug = "codex-remote-default-personality";
|
||||
let default_personality_message = "Default from remote template";
|
||||
let friendly_personality_message = "Friendly variant";
|
||||
let remote_model = ModelInfo {
|
||||
slug: remote_slug.to_string(),
|
||||
display_name: "Remote default personality test".to_string(),
|
||||
description: Some("Remote model with default personality template".to_string()),
|
||||
default_reasoning_level: Some(ReasoningEffort::Medium),
|
||||
supported_reasoning_levels: vec![ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: ReasoningEffort::Medium.to_string(),
|
||||
}],
|
||||
shell_type: ConfigShellToolType::UnifiedExec,
|
||||
visibility: ModelVisibility::List,
|
||||
supported_in_api: true,
|
||||
priority: 1,
|
||||
additional_speed_tiers: Vec::new(),
|
||||
service_tiers: Vec::new(),
|
||||
default_service_tier: None,
|
||||
available_access_programs: None,
|
||||
upgrade: None,
|
||||
model_messages: Some(ModelMessages {
|
||||
persistent_instructions: None,
|
||||
tools: None,
|
||||
instructions_template: Some("Base instructions\n{{ personality }}\n".to_string()),
|
||||
instructions_variables: Some(ModelInstructionsVariables {
|
||||
personality_default: Some(default_personality_message.to_string()),
|
||||
personality_friendly: Some(friendly_personality_message.to_string()),
|
||||
personality_pragmatic: Some("Pragmatic variant".to_string()),
|
||||
}),
|
||||
approvals: None,
|
||||
collaboration_modes: None,
|
||||
auto_review: None,
|
||||
permissions: None,
|
||||
multi_agent: None,
|
||||
token_budget: None,
|
||||
confirmation_policies: None,
|
||||
guardian_v2: None,
|
||||
}),
|
||||
include_skills_usage_instructions: false,
|
||||
include_plugin_usage_instructions: false,
|
||||
include_apps_usage_instructions: false,
|
||||
supports_reasoning_summary_parameter: true,
|
||||
default_reasoning_summary: ReasoningSummary::Auto,
|
||||
support_verbosity: false,
|
||||
default_verbosity: None,
|
||||
availability_nux: None,
|
||||
apply_patch_tool_type: None,
|
||||
web_search_tool_type: Default::default(),
|
||||
truncation_policy: TruncationPolicyConfig::bytes(/*limit*/ 10_000),
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(128_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
comp_hash: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
input_modalities: default_input_modalities(),
|
||||
used_fallback_model_metadata: false,
|
||||
supports_search_tool: false,
|
||||
supports_experimental_context: false,
|
||||
use_responses_lite: false,
|
||||
guardian: None,
|
||||
node_repl_auto_review_required: false,
|
||||
node_repl_disabled: false,
|
||||
auto_review_model_override: None,
|
||||
model_specialty: None,
|
||||
tool_mode: None,
|
||||
multi_agent_version: None,
|
||||
multi_agent_reasoning_effort: None,
|
||||
};
|
||||
|
||||
let _models_mock = mount_models_once(
|
||||
&server,
|
||||
ModelsResponse {
|
||||
models: vec![remote_model],
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_auth(codex_login::CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.model = Some(remote_slug.to_string());
|
||||
config.personality = Some(Personality::Friendly);
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
wait_for_model_available(&test.thread_manager.get_models_manager(), remote_slug).await;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn_with_personality(
|
||||
&test,
|
||||
"hello",
|
||||
remote_slug.to_string(),
|
||||
AskForApproval::Never,
|
||||
Some(Personality::Friendly),
|
||||
))
|
||||
.await?;
|
||||
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
let request = resp_mock.single_request();
|
||||
let instructions_text = request.instructions_text();
|
||||
|
||||
assert!(
|
||||
instructions_text.contains(friendly_personality_message),
|
||||
"expected instructions to include the remote friendly personality template, got: {instructions_text:?}"
|
||||
);
|
||||
assert!(
|
||||
!instructions_text.contains(default_personality_message),
|
||||
"expected instructions to skip the remote default personality template, got: {instructions_text:?}"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn user_turn_personality_remote_model_template_includes_update_message() -> anyhow::Result<()>
|
||||
{
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = MockServer::builder()
|
||||
.body_print_limit(BodyPrintLimit::Limited(80_000))
|
||||
.start()
|
||||
.await;
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let remote_slug = "codex-remote-personality";
|
||||
let remote_friendly_message = "Friendly from remote template";
|
||||
let remote_pragmatic_message = "Pragmatic from remote template";
|
||||
let remote_model = ModelInfo {
|
||||
slug: remote_slug.to_string(),
|
||||
display_name: "Remote personality test".to_string(),
|
||||
description: Some("Remote model with personality template".to_string()),
|
||||
default_reasoning_level: Some(ReasoningEffort::Medium),
|
||||
supported_reasoning_levels: vec![ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: ReasoningEffort::Medium.to_string(),
|
||||
}],
|
||||
shell_type: ConfigShellToolType::UnifiedExec,
|
||||
visibility: ModelVisibility::List,
|
||||
supported_in_api: true,
|
||||
priority: 1,
|
||||
additional_speed_tiers: Vec::new(),
|
||||
service_tiers: Vec::new(),
|
||||
default_service_tier: None,
|
||||
available_access_programs: None,
|
||||
upgrade: None,
|
||||
model_messages: Some(ModelMessages {
|
||||
persistent_instructions: None,
|
||||
tools: None,
|
||||
instructions_template: Some("Base instructions\n{{ personality }}\n".to_string()),
|
||||
instructions_variables: Some(ModelInstructionsVariables {
|
||||
personality_default: None,
|
||||
personality_friendly: Some(remote_friendly_message.to_string()),
|
||||
personality_pragmatic: Some(remote_pragmatic_message.to_string()),
|
||||
}),
|
||||
approvals: None,
|
||||
collaboration_modes: None,
|
||||
auto_review: None,
|
||||
permissions: None,
|
||||
multi_agent: None,
|
||||
token_budget: None,
|
||||
confirmation_policies: None,
|
||||
guardian_v2: None,
|
||||
}),
|
||||
include_skills_usage_instructions: false,
|
||||
include_plugin_usage_instructions: false,
|
||||
include_apps_usage_instructions: false,
|
||||
supports_reasoning_summary_parameter: true,
|
||||
default_reasoning_summary: ReasoningSummary::Auto,
|
||||
support_verbosity: false,
|
||||
default_verbosity: None,
|
||||
availability_nux: None,
|
||||
apply_patch_tool_type: None,
|
||||
web_search_tool_type: Default::default(),
|
||||
truncation_policy: TruncationPolicyConfig::bytes(/*limit*/ 10_000),
|
||||
supports_image_detail_original: false,
|
||||
context_window: Some(128_000),
|
||||
max_context_window: None,
|
||||
auto_compact_token_limit: None,
|
||||
comp_hash: None,
|
||||
effective_context_window_percent: 95,
|
||||
experimental_supported_tools: Vec::new(),
|
||||
input_modalities: default_input_modalities(),
|
||||
used_fallback_model_metadata: false,
|
||||
supports_search_tool: false,
|
||||
supports_experimental_context: false,
|
||||
use_responses_lite: false,
|
||||
guardian: None,
|
||||
node_repl_auto_review_required: false,
|
||||
node_repl_disabled: false,
|
||||
auto_review_model_override: None,
|
||||
model_specialty: None,
|
||||
tool_mode: None,
|
||||
multi_agent_version: None,
|
||||
multi_agent_reasoning_effort: None,
|
||||
};
|
||||
|
||||
let _models_mock = mount_models_once(
|
||||
let friendly = "Friendly from remote template";
|
||||
let pragmatic = "Pragmatic from remote template";
|
||||
let mut remote_model = bundled_models_response()?
|
||||
.models
|
||||
.into_iter()
|
||||
.find(|model| model.slug == "gpt-5.5")
|
||||
.expect("bundled gpt-5.5 model");
|
||||
remote_model.slug = remote_slug.to_string();
|
||||
remote_model.visibility = ModelVisibility::List;
|
||||
let messages = remote_model
|
||||
.model_messages
|
||||
.as_mut()
|
||||
.expect("model messages");
|
||||
messages.instructions_template = Some("Base instructions\n{{ personality }}\n".to_string());
|
||||
messages.instructions_variables = Some(ModelInstructionsVariables {
|
||||
personality_default: Some("Default from remote template".to_string()),
|
||||
personality_friendly: Some(friendly.to_string()),
|
||||
personality_pragmatic: Some(pragmatic.to_string()),
|
||||
});
|
||||
mount_models_once(
|
||||
&server,
|
||||
ModelsResponse {
|
||||
models: vec![remote_model],
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
let resp_mock = mount_sse_sequence(
|
||||
let responses = mount_sse_sequence(
|
||||
&server,
|
||||
vec![sse_completed("resp-1"), sse_completed("resp-2")],
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_auth(codex_login::CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_model(remote_slug)
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.model = Some("gpt-5.5".to_string());
|
||||
config.personality = Some(Personality::Friendly);
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
wait_for_model_available(&test.thread_manager.get_models_manager(), remote_slug).await;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn(
|
||||
&test,
|
||||
"hello",
|
||||
remote_slug.to_string(),
|
||||
AskForApproval::Never,
|
||||
))
|
||||
.await?;
|
||||
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
test.submit_turn("first turn").await?;
|
||||
|
||||
core_test_support::submit_thread_settings(
|
||||
&test.codex,
|
||||
ThreadSettingsOverrides {
|
||||
personality: Some(Personality::Friendly),
|
||||
personality: Some(Personality::Pragmatic),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
test.submit_turn("use the pragmatic selection").await?;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn(
|
||||
&test,
|
||||
"hello",
|
||||
remote_slug.to_string(),
|
||||
AskForApproval::Never,
|
||||
))
|
||||
.await?;
|
||||
|
||||
wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
let requests = resp_mock.requests();
|
||||
assert_eq!(requests.len(), 2, "expected two requests");
|
||||
let request = requests
|
||||
.last()
|
||||
.expect("expected personality update request");
|
||||
let developer_texts = request.message_input_texts("developer");
|
||||
let requests = responses.requests();
|
||||
assert_eq!(requests.len(), 2);
|
||||
assert_eq!(
|
||||
requests[0].instructions_text(),
|
||||
format!("Base instructions\n{friendly}\n")
|
||||
);
|
||||
let developer_texts = requests[1].message_input_texts("developer");
|
||||
let personality_text = developer_texts
|
||||
.iter()
|
||||
.find(|text| text.contains(remote_friendly_message))
|
||||
.expect("expected personality update message in developer input");
|
||||
.find(|text| text.contains("<personality_spec>"))
|
||||
.expect("expected personality update message");
|
||||
assert!(personality_text.contains("The user has requested a new communication style."));
|
||||
assert!(personality_text.contains(pragmatic));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
assert!(
|
||||
personality_text.contains("The user has requested a new communication style."),
|
||||
"expected personality update preamble, got {personality_text:?}"
|
||||
#[test_case("gpt-5.4", LOCAL_FRIENDLY_TEMPLATE; "gpt_5_4")]
|
||||
#[test_case("gpt-5.5", BUNDLED_FRIENDLY_TEMPLATE; "gpt_5_5")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn fixed_friendly_personality_ignores_pragmatic_update(
|
||||
model: &str,
|
||||
friendly_template: &str,
|
||||
) -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let responses = mount_sse_sequence(
|
||||
&server,
|
||||
vec![sse_completed("resp-1"), sse_completed("resp-2")],
|
||||
)
|
||||
.await;
|
||||
let mut builder = test_codex().with_model(model).with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::Friendly);
|
||||
});
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
test.submit_turn("first turn").await?;
|
||||
|
||||
core_test_support::submit_thread_settings(
|
||||
&test.codex,
|
||||
ThreadSettingsOverrides {
|
||||
personality: Some(Personality::Pragmatic),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
test.submit_turn("continue with the legacy pragmatic setting")
|
||||
.await?;
|
||||
|
||||
let requests = responses.requests();
|
||||
assert_eq!(requests.len(), 2);
|
||||
assert!(requests[0].instructions_text().contains(friendly_template));
|
||||
assert_eq!(
|
||||
requests[1].instructions_text(),
|
||||
requests[0].instructions_text()
|
||||
);
|
||||
assert!(
|
||||
personality_text.contains(remote_friendly_message),
|
||||
"expected personality update to include remote template, got: {personality_text:?}"
|
||||
requests
|
||||
.iter()
|
||||
.all(|request| !request.body_contains_text("<personality_spec>"))
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn legacy_personality_session_resumes_and_completes() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let responses = mount_sse_sequence(
|
||||
&server,
|
||||
vec![sse_completed("resp-1"), sse_completed("resp-2")],
|
||||
)
|
||||
.await;
|
||||
let legacy_instructions = "Legacy model instructions\n# Personality\nBe pragmatic.";
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| {
|
||||
config.personality = Some(Personality::Pragmatic);
|
||||
config.base_instructions = Some(legacy_instructions.to_string());
|
||||
config.base_instructions_provenance = Some(BaseInstructionsProvenance::Model {
|
||||
model: "gpt-5.5".to_string(),
|
||||
});
|
||||
});
|
||||
let original = builder.build_with_auto_env(&server).await?;
|
||||
original.submit_turn("first turn").await?;
|
||||
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config.personality = Some(Personality::None);
|
||||
});
|
||||
let resumed = builder.restart(&server, &original).await?;
|
||||
assert_eq!(
|
||||
resumed.session_configured.thread_id,
|
||||
original.session_configured.thread_id
|
||||
);
|
||||
resumed.submit_turn("continue the existing session").await?;
|
||||
|
||||
let requests = responses.requests();
|
||||
assert_eq!(requests.len(), 2);
|
||||
assert_eq!(requests[1].instructions_text(), legacy_instructions);
|
||||
assert!(
|
||||
requests[1]
|
||||
.message_input_texts("user")
|
||||
.iter()
|
||||
.any(|text| text == "first turn")
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -1,8 +1,9 @@
|
||||
---
|
||||
source: core/tests/suite/model_visible_layout.rs
|
||||
expression: "format_labeled_requests_snapshot(\"Second turn changes cwd, approval policy, and personality while keeping model constant.\",\n&[(\"First Request (Baseline)\", &requests[0]),\n(\"Second Request (Turn Overrides)\", &requests[1]),])"
|
||||
assertion_line: 360
|
||||
expression: "format_labeled_requests_snapshot(\"Second turn changes cwd and approval policy while keeping model constant.\",\n&[(\"First Request (Baseline)\", &requests[0]),\n(\"Second Request (Turn Overrides)\", &requests[1]),])"
|
||||
---
|
||||
Scenario: Second turn changes cwd, approval policy, and personality while keeping model constant.
|
||||
Scenario: Second turn changes cwd and approval policy while keeping model constant.
|
||||
|
||||
## First Request (Baseline)
|
||||
00:message/developer[2]:
|
||||
@@ -18,7 +19,6 @@ Scenario: Second turn changes cwd, approval policy, and personality while keepin
|
||||
01:message/user:<ENVIRONMENT_CONTEXT:cwd=<CWD>>
|
||||
02:message/user:first turn
|
||||
03:message/assistant:turn one complete
|
||||
04:message/developer:<personality_spec> The user has requested a new communication style. Future messages should adhe...
|
||||
05:message/developer:<PERMISSIONS_INSTRUCTIONS>
|
||||
06:message/user:<ENVIRONMENT_CONTEXT:cwd=PRETURN_CONTEXT_DIFF_CWD>
|
||||
07:message/user:second turn with context updates
|
||||
04:message/developer:<PERMISSIONS_INSTRUCTIONS>
|
||||
05:message/user:<ENVIRONMENT_CONTEXT:cwd=PRETURN_CONTEXT_DIFF_CWD>
|
||||
06:message/user:second turn with context updates
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1329,10 +1329,7 @@ async fn enter_submits_when_plan_stream_is_not_active() {
|
||||
|
||||
assert!(chat.input_queue.queued_user_messages.is_empty());
|
||||
match next_submit_op(&mut op_rx) {
|
||||
Op::UserTurn {
|
||||
personality: Some(Personality::Pragmatic),
|
||||
..
|
||||
} => {}
|
||||
Op::UserTurn { .. } => {}
|
||||
other => panic!("expected Op::UserTurn, got {other:?}"),
|
||||
}
|
||||
}
|
||||
@@ -1720,7 +1717,6 @@ async fn collab_mode_is_sent_after_enabling() {
|
||||
mode: ModeKind::Default,
|
||||
..
|
||||
}),
|
||||
personality: Some(Personality::Pragmatic),
|
||||
..
|
||||
} => {}
|
||||
other => {
|
||||
@@ -1744,7 +1740,6 @@ async fn collab_mode_applies_default_preset() {
|
||||
mode: ModeKind::Default,
|
||||
..
|
||||
}),
|
||||
personality: Some(Personality::Pragmatic),
|
||||
..
|
||||
} => {}
|
||||
other => {
|
||||
@@ -1758,21 +1753,49 @@ async fn collab_mode_applies_default_preset() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn user_turn_includes_personality_from_config() {
|
||||
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.5")).await;
|
||||
chat.set_feature_enabled(Feature::Personality, /*enabled*/ true);
|
||||
chat.thread_id = Some(ThreadId::new());
|
||||
chat.set_model("gpt-5.5");
|
||||
chat.set_personality(Personality::Friendly);
|
||||
for configured_personality in [
|
||||
Personality::Friendly,
|
||||
Personality::Pragmatic,
|
||||
Personality::None,
|
||||
] {
|
||||
let preset = crate::test_support::legacy_personality_model_preset();
|
||||
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some(&preset.model)).await;
|
||||
Arc::make_mut(&mut chat.model_catalog).models = vec![preset];
|
||||
chat.set_feature_enabled(Feature::Personality, /*enabled*/ true);
|
||||
chat.thread_id = Some(ThreadId::new());
|
||||
chat.set_personality(configured_personality);
|
||||
|
||||
chat.bottom_pane
|
||||
.set_composer_text("hello".to_string(), Vec::new(), Vec::new());
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
|
||||
match next_submit_op(&mut op_rx) {
|
||||
Op::UserTurn {
|
||||
personality: Some(Personality::Friendly),
|
||||
..
|
||||
} => {}
|
||||
other => panic!("expected Op::UserTurn with friendly personality, got {other:?}"),
|
||||
chat.bottom_pane
|
||||
.set_composer_text("hello".to_string(), Vec::new(), Vec::new());
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
|
||||
let Op::UserTurn { personality, .. } = next_submit_op(&mut op_rx) else {
|
||||
panic!("expected Op::UserTurn");
|
||||
};
|
||||
assert_eq!(personality, Some(configured_personality));
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn user_turn_omits_personality_for_fixed_personality_models() {
|
||||
for model in ["gpt-5.4", "gpt-5.5"] {
|
||||
for configured_personality in [
|
||||
Personality::Friendly,
|
||||
Personality::Pragmatic,
|
||||
Personality::None,
|
||||
] {
|
||||
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some(model)).await;
|
||||
chat.set_feature_enabled(Feature::Personality, /*enabled*/ true);
|
||||
chat.thread_id = Some(ThreadId::new());
|
||||
chat.set_personality(configured_personality);
|
||||
|
||||
chat.bottom_pane
|
||||
.set_composer_text("hello".to_string(), Vec::new(), Vec::new());
|
||||
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
|
||||
let Op::UserTurn { personality, .. } = next_submit_op(&mut op_rx) else {
|
||||
panic!("expected Op::UserTurn");
|
||||
};
|
||||
assert_eq!(personality, None, "model: {model}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3591,14 +3591,35 @@ async fn model_picker_refresh_dismisses_empty_choices() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn personality_selection_popup_snapshot() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.5")).await;
|
||||
let preset = crate::test_support::legacy_personality_model_preset();
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some(&preset.model)).await;
|
||||
Arc::make_mut(&mut chat.model_catalog).models = vec![preset];
|
||||
chat.thread_id = Some(ThreadId::new());
|
||||
chat.set_personality(Personality::Pragmatic);
|
||||
chat.open_personality_popup();
|
||||
|
||||
let popup = render_bottom_popup(&chat, /*width*/ 80);
|
||||
assert_chatwidget_snapshot!("personality_selection_popup", popup);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn personality_selection_is_unavailable_for_fixed_personality_models() {
|
||||
for model in ["gpt-5.4", "gpt-5.5"] {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some(model)).await;
|
||||
chat.thread_id = Some(ThreadId::new());
|
||||
while rx.try_recv().is_ok() {}
|
||||
|
||||
chat.open_personality_popup();
|
||||
|
||||
assert!(!chat.bottom_pane.has_active_view());
|
||||
let cell = assert_matches!(rx.try_recv(), Ok(AppEvent::InsertHistoryCell(cell)) => cell);
|
||||
let message = lines_to_single_string(&cell.display_lines(/*width*/ 120));
|
||||
assert!(message.contains(&format!(
|
||||
"Current model ({model}) doesn't support personalities."
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn skills_menu_default_mentions_shortcut_snapshot() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
|
||||
@@ -4,6 +4,9 @@ use std::sync::LazyLock;
|
||||
|
||||
use codex_models_manager::bundled_models_response;
|
||||
use codex_protocol::openai_models::ModelPreset;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
use codex_protocol::openai_models::ReasoningEffortPreset;
|
||||
use codex_protocol::openai_models::default_input_modalities;
|
||||
pub(crate) use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
pub(crate) use codex_utils_absolute_path::test_support::test_path_buf;
|
||||
use serde::Serialize;
|
||||
@@ -18,6 +21,34 @@ pub(crate) static TEST_MODEL_PRESETS: LazyLock<Vec<ModelPreset>> = LazyLock::new
|
||||
presets
|
||||
});
|
||||
|
||||
/// A legacy catalog entry whose personality remains selectable, independent of bundled models.
|
||||
pub(crate) fn legacy_personality_model_preset() -> ModelPreset {
|
||||
ModelPreset {
|
||||
id: "legacy-personality-model".to_string(),
|
||||
model: "legacy-personality-model".to_string(),
|
||||
display_name: "Legacy personality model".to_string(),
|
||||
description: "Test model with selectable personalities.".to_string(),
|
||||
model_specialty: None,
|
||||
default_reasoning_effort: ReasoningEffort::Medium,
|
||||
supported_reasoning_efforts: vec![ReasoningEffortPreset {
|
||||
effort: ReasoningEffort::Medium,
|
||||
description: "medium".to_string(),
|
||||
}],
|
||||
supports_personality: true,
|
||||
additional_speed_tiers: Vec::new(),
|
||||
service_tiers: Vec::new(),
|
||||
default_service_tier: None,
|
||||
available_access_programs: None,
|
||||
is_default: false,
|
||||
upgrade: None,
|
||||
show_in_picker: true,
|
||||
multi_agent_version: None,
|
||||
availability_nux: None,
|
||||
supported_in_api: true,
|
||||
input_modalities: default_input_modalities(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn test_path_display(path: &str) -> String {
|
||||
test_path_buf(path).display().to_string()
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ from openai_codex import (
|
||||
AsyncCodex,
|
||||
)
|
||||
from openai_codex.types import (
|
||||
Personality,
|
||||
ReasoningSummary,
|
||||
)
|
||||
|
||||
@@ -50,7 +49,6 @@ async def main() -> None:
|
||||
turn = await thread.turn(
|
||||
PROMPT,
|
||||
output_schema=OUTPUT_SCHEMA,
|
||||
personality=Personality.pragmatic,
|
||||
summary=SUMMARY,
|
||||
)
|
||||
result = await turn.run()
|
||||
|
||||
@@ -14,7 +14,6 @@ from openai_codex import (
|
||||
Codex,
|
||||
)
|
||||
from openai_codex.types import (
|
||||
Personality,
|
||||
ReasoningSummary,
|
||||
)
|
||||
|
||||
@@ -44,7 +43,6 @@ with Codex(config=runtime_config()) as codex:
|
||||
turn = thread.turn(
|
||||
PROMPT,
|
||||
output_schema=OUTPUT_SCHEMA,
|
||||
personality=Personality.pragmatic,
|
||||
summary=SUMMARY,
|
||||
)
|
||||
result = turn.run()
|
||||
|
||||
@@ -16,7 +16,6 @@ from openai_codex import (
|
||||
Sandbox,
|
||||
)
|
||||
from openai_codex.types import (
|
||||
Personality,
|
||||
ReasoningEffort,
|
||||
ReasoningSummary,
|
||||
)
|
||||
@@ -100,7 +99,6 @@ async def main() -> None:
|
||||
effort=selected_effort,
|
||||
model=selected_model.model,
|
||||
output_schema=OUTPUT_SCHEMA,
|
||||
personality=Personality.pragmatic,
|
||||
sandbox=Sandbox.read_only,
|
||||
summary=ReasoningSummary.model_validate("concise"),
|
||||
)
|
||||
|
||||
@@ -14,7 +14,6 @@ from openai_codex import (
|
||||
Sandbox,
|
||||
)
|
||||
from openai_codex.types import (
|
||||
Personality,
|
||||
ReasoningEffort,
|
||||
ReasoningSummary,
|
||||
)
|
||||
@@ -95,7 +94,6 @@ with Codex(config=runtime_config()) as codex:
|
||||
effort=selected_effort,
|
||||
model=selected_model.model,
|
||||
output_schema=OUTPUT_SCHEMA,
|
||||
personality=Personality.pragmatic,
|
||||
sandbox=Sandbox.read_only,
|
||||
summary=ReasoningSummary.model_validate("concise"),
|
||||
).run()
|
||||
|
||||
@@ -222,7 +222,6 @@
|
||||
"from pathlib import Path\n",
|
||||
"from openai_codex import Sandbox\n",
|
||||
"from openai_codex.types import (\n",
|
||||
" Personality,\n",
|
||||
" ReasoningEffort,\n",
|
||||
" ReasoningSummary,\n",
|
||||
")\n",
|
||||
@@ -247,7 +246,6 @@
|
||||
" effort=ReasoningEffort.medium,\n",
|
||||
" model='gpt-5.4',\n",
|
||||
" output_schema=output_schema,\n",
|
||||
" personality=Personality.pragmatic,\n",
|
||||
" sandbox=Sandbox.read_only,\n",
|
||||
" summary=summary,\n",
|
||||
" )\n",
|
||||
@@ -267,7 +265,6 @@
|
||||
"from pathlib import Path\n",
|
||||
"from openai_codex import Sandbox\n",
|
||||
"from openai_codex.types import (\n",
|
||||
" Personality,\n",
|
||||
" ReasoningEffort,\n",
|
||||
" ReasoningSummary,\n",
|
||||
")\n",
|
||||
@@ -334,7 +331,6 @@
|
||||
" effort=selected_effort,\n",
|
||||
" model=selected_model.model,\n",
|
||||
" output_schema=output_schema,\n",
|
||||
" personality=Personality.pragmatic,\n",
|
||||
" sandbox=Sandbox.read_only,\n",
|
||||
" summary=ReasoningSummary.model_validate('concise'),\n",
|
||||
" ).run()\n",
|
||||
|
||||
Reference in New Issue
Block a user