mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Support --output-schema for exec resume (#23123)
## Why `codex exec resume` should have the same structured-output support as top-level `codex exec`. Without `--output-schema`, multi-turn automation has to choose between resumed session context and schema-validated JSON output. Fixes #22998. ## What changed - Marked `--output-schema` as a global `codex exec` flag so it can be passed after `resume`. - Reused the existing output schema plumbing so resumed turns attach the schema to the final response request while preserving session context.
This commit is contained in:
committed by
GitHub
Unverified
parent
fce10e009d
commit
af6ffb6ebb
@@ -50,7 +50,7 @@ pub struct Cli {
|
||||
pub removed_full_auto: bool,
|
||||
|
||||
/// Path to a JSON Schema file describing the model's final response shape.
|
||||
#[arg(long = "output-schema", value_name = "FILE")]
|
||||
#[arg(long = "output-schema", value_name = "FILE", global = true)]
|
||||
pub output_schema: Option<PathBuf>,
|
||||
|
||||
#[clap(skip)]
|
||||
|
||||
@@ -36,7 +36,7 @@ fn resume_parses_prompt_after_global_flags() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resume_accepts_output_last_message_flag_after_subcommand() {
|
||||
fn resume_accepts_output_flags_after_subcommand() {
|
||||
const PROMPT: &str = "echo resume-with-output-file";
|
||||
let cli = Cli::parse_from([
|
||||
"codex-exec",
|
||||
@@ -44,6 +44,8 @@ fn resume_accepts_output_last_message_flag_after_subcommand() {
|
||||
"session-123",
|
||||
"-o",
|
||||
"/tmp/resume-output.md",
|
||||
"--output-schema",
|
||||
"/tmp/schema.json",
|
||||
PROMPT,
|
||||
]);
|
||||
|
||||
@@ -51,6 +53,7 @@ fn resume_accepts_output_last_message_flag_after_subcommand() {
|
||||
cli.last_message_file,
|
||||
Some(PathBuf::from("/tmp/resume-output.md"))
|
||||
);
|
||||
assert_eq!(cli.output_schema, Some(PathBuf::from("/tmp/schema.json")));
|
||||
let Some(Command::Resume(args)) = cli.command else {
|
||||
panic!("expected resume command");
|
||||
};
|
||||
|
||||
@@ -375,6 +375,62 @@ async fn exec_resume_accepts_global_flags_after_subcommand() -> anyhow::Result<(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn exec_resume_includes_output_schema_in_request() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let test = test_codex_exec();
|
||||
let server = MockServer::start().await;
|
||||
let response_mock = mount_exec_responses(&server, /*count*/ 2).await;
|
||||
|
||||
let schema_contents = serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"answer": { "type": "string" }
|
||||
},
|
||||
"required": ["answer"],
|
||||
"additionalProperties": false
|
||||
});
|
||||
let schema_path = test.cwd_path().join("schema.json");
|
||||
std::fs::write(&schema_path, serde_json::to_vec_pretty(&schema_contents)?)?;
|
||||
|
||||
test.cmd_with_server(&server)
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("echo seed-resume-session")
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
test.cmd_with_server(&server)
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("resume")
|
||||
.arg("--last")
|
||||
.arg("--json")
|
||||
.arg("--output-schema")
|
||||
.arg(&schema_path)
|
||||
.arg("echo resume-with-schema")
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let requests = response_mock.requests();
|
||||
assert_eq!(requests.len(), 2);
|
||||
let payload: Value = requests[1].body_json();
|
||||
let text = payload.get("text").expect("request missing text field");
|
||||
let format = text
|
||||
.get("format")
|
||||
.expect("request missing text.format field");
|
||||
assert_eq!(
|
||||
format,
|
||||
&serde_json::json!({
|
||||
"name": "codex_output_schema",
|
||||
"type": "json_schema",
|
||||
"strict": true,
|
||||
"schema": schema_contents,
|
||||
})
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn exec_resume_by_id_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
Reference in New Issue
Block a user