mirror of
https://github.com/openai/codex.git
synced 2026-05-03 10:56:37 +00:00
Validate exec input before starting app-server (#16890)
Addresses #16443 This was a regression introduced when we moved exec on top of the app server APIs. Problem: codex exec resolved prompt/stdin and output schema after starting the in-process app-server, so early `process::exit(1)` paths could bypass session shutdown. Solution: Resolve prompt/stdin and output schema before app-server startup so validation failures happen before any exec session is created.
This commit is contained in:
@@ -514,6 +514,66 @@ async fn run_exec_session(args: ExecRunArgs) -> anyhow::Result<()> {
|
||||
let default_sandbox_policy = config.permissions.sandbox_policy.get();
|
||||
let default_effort = config.model_reasoning_effort;
|
||||
|
||||
let (initial_operation, prompt_summary) = match (command.as_ref(), prompt, images) {
|
||||
(Some(ExecCommand::Review(review_cli)), _, _) => {
|
||||
let review_request = build_review_request(review_cli)?;
|
||||
let summary = codex_core::review_prompts::user_facing_hint(&review_request.target);
|
||||
(InitialOperation::Review { review_request }, summary)
|
||||
}
|
||||
(Some(ExecCommand::Resume(args)), root_prompt, imgs) => {
|
||||
let prompt_arg = args
|
||||
.prompt
|
||||
.clone()
|
||||
.or_else(|| {
|
||||
if args.last {
|
||||
args.session_id.clone()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.or(root_prompt);
|
||||
let prompt_text = resolve_prompt(prompt_arg);
|
||||
let mut items: Vec<UserInput> = imgs
|
||||
.into_iter()
|
||||
.chain(args.images.iter().cloned())
|
||||
.map(|path| UserInput::LocalImage { path })
|
||||
.collect();
|
||||
items.push(UserInput::Text {
|
||||
text: prompt_text.clone(),
|
||||
// CLI input doesn't track UI element ranges, so none are available here.
|
||||
text_elements: Vec::new(),
|
||||
});
|
||||
let output_schema = load_output_schema(output_schema_path.clone());
|
||||
(
|
||||
InitialOperation::UserTurn {
|
||||
items,
|
||||
output_schema,
|
||||
},
|
||||
prompt_text,
|
||||
)
|
||||
}
|
||||
(None, root_prompt, imgs) => {
|
||||
let prompt_text = resolve_root_prompt(root_prompt);
|
||||
let mut items: Vec<UserInput> = imgs
|
||||
.into_iter()
|
||||
.map(|path| UserInput::LocalImage { path })
|
||||
.collect();
|
||||
items.push(UserInput::Text {
|
||||
text: prompt_text.clone(),
|
||||
// CLI input doesn't track UI element ranges, so none are available here.
|
||||
text_elements: Vec::new(),
|
||||
});
|
||||
let output_schema = load_output_schema(output_schema_path);
|
||||
(
|
||||
InitialOperation::UserTurn {
|
||||
items,
|
||||
output_schema,
|
||||
},
|
||||
prompt_text,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// When --yolo (dangerously_bypass_approvals_and_sandbox) is set, also skip the git repo check
|
||||
// since the user is explicitly running in an externally sandboxed environment.
|
||||
if !skip_git_repo_check
|
||||
@@ -588,66 +648,6 @@ async fn run_exec_session(args: ExecRunArgs) -> anyhow::Result<()> {
|
||||
|
||||
exec_span.record("thread.id", primary_thread_id_for_span.as_str());
|
||||
|
||||
let (initial_operation, prompt_summary) = match (command.as_ref(), prompt, images) {
|
||||
(Some(ExecCommand::Review(review_cli)), _, _) => {
|
||||
let review_request = build_review_request(review_cli)?;
|
||||
let summary = codex_core::review_prompts::user_facing_hint(&review_request.target);
|
||||
(InitialOperation::Review { review_request }, summary)
|
||||
}
|
||||
(Some(ExecCommand::Resume(args)), root_prompt, imgs) => {
|
||||
let prompt_arg = args
|
||||
.prompt
|
||||
.clone()
|
||||
.or_else(|| {
|
||||
if args.last {
|
||||
args.session_id.clone()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.or(root_prompt);
|
||||
let prompt_text = resolve_prompt(prompt_arg);
|
||||
let mut items: Vec<UserInput> = imgs
|
||||
.into_iter()
|
||||
.chain(args.images.iter().cloned())
|
||||
.map(|path| UserInput::LocalImage { path })
|
||||
.collect();
|
||||
items.push(UserInput::Text {
|
||||
text: prompt_text.clone(),
|
||||
// CLI input doesn't track UI element ranges, so none are available here.
|
||||
text_elements: Vec::new(),
|
||||
});
|
||||
let output_schema = load_output_schema(output_schema_path.clone());
|
||||
(
|
||||
InitialOperation::UserTurn {
|
||||
items,
|
||||
output_schema,
|
||||
},
|
||||
prompt_text,
|
||||
)
|
||||
}
|
||||
(None, root_prompt, imgs) => {
|
||||
let prompt_text = resolve_root_prompt(root_prompt);
|
||||
let mut items: Vec<UserInput> = imgs
|
||||
.into_iter()
|
||||
.map(|path| UserInput::LocalImage { path })
|
||||
.collect();
|
||||
items.push(UserInput::Text {
|
||||
text: prompt_text.clone(),
|
||||
// CLI input doesn't track UI element ranges, so none are available here.
|
||||
text_elements: Vec::new(),
|
||||
});
|
||||
let output_schema = load_output_schema(output_schema_path);
|
||||
(
|
||||
InitialOperation::UserTurn {
|
||||
items,
|
||||
output_schema,
|
||||
},
|
||||
prompt_text,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Print the effective configuration and initial request so users can see what Codex
|
||||
// is using.
|
||||
event_processor.print_config_summary(&config, &prompt_summary, &session_configured);
|
||||
|
||||
Reference in New Issue
Block a user