turn metadata: per-turn non-blocking (#11677)

This commit is contained in:
pash-openai
2026-02-13 12:48:29 -08:00
committed by GitHub
parent a4bb59884b
commit 6c0a924203
11 changed files with 457 additions and 158 deletions

View File

@@ -375,6 +375,15 @@ async fn responses_stream_includes_turn_metadata_header_for_git_workspace_e2e()
.expect("x-codex-turn-metadata header should be present");
let initial_parsed: serde_json::Value =
serde_json::from_str(&initial_header).expect("x-codex-turn-metadata should be valid JSON");
let initial_turn_id = initial_parsed
.get("turn_id")
.and_then(serde_json::Value::as_str)
.expect("turn_id should be present")
.to_string();
assert!(
!initial_turn_id.is_empty(),
"turn_id should not be empty in x-codex-turn-metadata"
);
assert_eq!(
initial_parsed
.get("sandbox")
@@ -424,56 +433,95 @@ async fn responses_stream_includes_turn_metadata_header_for_git_workspace_e2e()
.trim()
.to_string();
let deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(5);
loop {
let request_recorder = responses::mount_sse_once(&server, response_body.clone()).await;
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
test.submit_turn("hello")
.await
.expect("submit post-git turn prompt");
let first_response = responses::sse(vec![
responses::ev_response_created("resp-2"),
responses::ev_reasoning_item("rsn-1", &["thinking"], &[]),
responses::ev_shell_command_call("call-1", "echo turn-metadata"),
responses::ev_completed("resp-2"),
]);
let follow_up_response = responses::sse(vec![
responses::ev_response_created("resp-3"),
responses::ev_assistant_message("msg-1", "done"),
responses::ev_completed("resp-3"),
]);
let request_log = responses::mount_response_sequence(
&server,
vec![
responses::sse_response(first_response),
responses::sse_response(follow_up_response),
],
)
.await;
let maybe_metadata = request_recorder
.single_request()
test.submit_turn("hello")
.await
.expect("submit post-git turn prompt");
let requests = request_log.requests();
assert_eq!(requests.len(), 2, "expected two requests in one turn");
let first_parsed: serde_json::Value = serde_json::from_str(
&requests[0]
.header("x-codex-turn-metadata")
.and_then(|header_value| {
let parsed: serde_json::Value = serde_json::from_str(&header_value).ok()?;
let workspace = parsed
.get("workspaces")
.and_then(serde_json::Value::as_object)
.and_then(|workspaces| workspaces.values().next())
.cloned()?;
Some((parsed, workspace))
});
let Some((parsed, workspace)) = maybe_metadata else {
if tokio::time::Instant::now() >= deadline {
break;
}
tokio::time::sleep(std::time::Duration::from_millis(25)).await;
continue;
};
.expect("first request should include turn metadata"),
)
.expect("first metadata should be valid json");
let second_parsed: serde_json::Value = serde_json::from_str(
&requests[1]
.header("x-codex-turn-metadata")
.expect("second request should include turn metadata"),
)
.expect("second metadata should be valid json");
assert_eq!(
parsed.get("sandbox").and_then(serde_json::Value::as_str),
Some("none")
);
assert_eq!(
workspace
.get("latest_git_commit_hash")
.and_then(serde_json::Value::as_str),
Some(expected_head.as_str())
);
assert_eq!(
workspace
.get("associated_remote_urls")
.and_then(serde_json::Value::as_object)
.and_then(|remotes| remotes.get("origin"))
.and_then(serde_json::Value::as_str),
Some(expected_origin.as_str())
);
return;
}
let first_turn_id = first_parsed
.get("turn_id")
.and_then(serde_json::Value::as_str)
.expect("first turn_id should be present");
let second_turn_id = second_parsed
.get("turn_id")
.and_then(serde_json::Value::as_str)
.expect("second turn_id should be present");
assert_eq!(
first_turn_id, second_turn_id,
"requests should share turn_id"
);
assert_ne!(
second_turn_id,
initial_turn_id.as_str(),
"post-git turn should have a new turn_id"
);
panic!(
"x-codex-turn-metadata with git workspace info was never observed within 5s after git setup"
assert_eq!(
second_parsed
.get("sandbox")
.and_then(serde_json::Value::as_str),
Some("none")
);
let workspace = second_parsed
.get("workspaces")
.and_then(serde_json::Value::as_object)
.and_then(|workspaces| workspaces.values().next())
.cloned()
.expect("second request should include git workspace metadata");
assert_eq!(
workspace
.get("latest_git_commit_hash")
.and_then(serde_json::Value::as_str),
Some(expected_head.as_str())
);
assert_eq!(
workspace
.get("associated_remote_urls")
.and_then(serde_json::Value::as_object)
.and_then(|remotes| remotes.get("origin"))
.and_then(serde_json::Value::as_str),
Some(expected_origin.as_str())
);
assert_eq!(
workspace
.get("has_changes")
.and_then(serde_json::Value::as_bool),
Some(false)
);
}