Keep parent request values in turn metadata only

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
nicholasclark-openai
2026-03-19 13:13:06 -07:00
parent ec278abd94
commit 5bf604ca69
5 changed files with 51 additions and 117 deletions

View File

@@ -863,7 +863,7 @@ mod tests {
}
#[tokio::test]
async fn in_process_start_forwards_turn_metadata_headers_on_turn_requests() {
async fn in_process_start_forwards_turn_metadata_on_turn_requests() {
let server = create_mock_responses_server_repeating_assistant("Done").await;
let codex_home = TempDir::new().expect("tempdir should create");
let mut client = start(InProcessStartArgs {
@@ -1004,26 +1004,25 @@ mod tests {
.expect("timed out waiting for outbound requests");
assert!(!requests.is_empty());
for request in requests {
let turn_metadata_header = request
.headers
.get("x-codex-turn-metadata")
.and_then(|value| value.to_str().ok())
.expect("turn metadata header should be present");
let turn_metadata: serde_json::Value =
serde_json::from_str(turn_metadata_header).expect("turn metadata should be JSON");
assert_eq!(
request
.headers
.get("x-openai-parent-conversation-id")
.and_then(|value| value.to_str().ok()),
Some("parent-conversation-123")
turn_metadata.pointer("/metadata/parentConversationId"),
Some(&serde_json::json!("parent-conversation-123"))
);
assert_eq!(
request
.headers
.get("x-openai-parent-message-id")
.and_then(|value| value.to_str().ok()),
Some("parent-message-123")
turn_metadata.pointer("/metadata/parentMessageId"),
Some(&serde_json::json!("parent-message-123"))
);
assert_eq!(
request
.headers
.get("x-openai-parent-turn-id")
.and_then(|value| value.to_str().ok()),
Some("parent-turn-123")
turn_metadata.pointer("/metadata/parentTurnId"),
Some(&serde_json::json!("parent-turn-123"))
);
}

View File

@@ -108,7 +108,6 @@ use crate::response_debug_context::extract_response_debug_context_from_api_error
use crate::response_debug_context::telemetry_api_error_message;
use crate::response_debug_context::telemetry_transport_error_message;
use crate::tools::spec::create_tools_json_for_responses_api;
use crate::turn_metadata::extend_known_request_headers;
use crate::util::FeedbackRequestTags;
use crate::util::emit_feedback_auth_recovery_tags;
use crate::util::emit_feedback_request_tags_with_auth_env;
@@ -1385,10 +1384,6 @@ fn build_responses_headers(
turn_metadata_header: Option<&HeaderValue>,
) -> ApiHeaderMap {
let mut headers = ApiHeaderMap::new();
extend_known_request_headers(
&mut headers,
turn_metadata_header.and_then(|value| value.to_str().ok()),
);
if let Some(value) = beta_features_header
&& !value.is_empty()
&& let Ok(header_value) = HeaderValue::from_str(value)

View File

@@ -5,9 +5,6 @@ use std::sync::Arc;
use std::sync::Mutex;
use std::sync::RwLock;
use http::HeaderMap;
use http::HeaderValue;
use serde::Deserialize;
use serde::Serialize;
use tokio::task::JoinHandle;
@@ -19,14 +16,6 @@ use crate::sandbox_tags::sandbox_tag;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::protocol::SandboxPolicy;
pub(crate) const PARENT_CONVERSATION_ID_METADATA_KEY: &str = "parentConversationId";
pub(crate) const PARENT_MESSAGE_ID_METADATA_KEY: &str = "parentMessageId";
pub(crate) const PARENT_TURN_ID_METADATA_KEY: &str = "parentTurnId";
const X_OPENAI_PARENT_CONVERSATION_ID_HEADER: &str = "x-openai-parent-conversation-id";
const X_OPENAI_PARENT_MESSAGE_ID_HEADER: &str = "x-openai-parent-message-id";
const X_OPENAI_PARENT_TURN_ID_HEADER: &str = "x-openai-parent-turn-id";
#[derive(Clone, Debug, Default)]
struct WorkspaceGitMetadata {
associated_remote_urls: Option<BTreeMap<String, String>>,
@@ -42,7 +31,7 @@ impl WorkspaceGitMetadata {
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
#[derive(Clone, Debug, Serialize, Default)]
struct TurnMetadataWorkspace {
#[serde(default, skip_serializing_if = "Option::is_none")]
associated_remote_urls: Option<BTreeMap<String, String>>,
@@ -62,7 +51,7 @@ impl From<WorkspaceGitMetadata> for TurnMetadataWorkspace {
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
#[derive(Clone, Debug, Serialize, Default)]
pub(crate) struct TurnMetadataBag {
#[serde(default, skip_serializing_if = "Option::is_none")]
session_id: Option<String>,
@@ -267,52 +256,6 @@ impl TurnMetadataState {
}
}
}
pub(crate) fn extend_known_request_headers(
headers: &mut HeaderMap,
turn_metadata_header: Option<&str>,
) {
let Some(turn_metadata_header) = turn_metadata_header else {
return;
};
let Ok(turn_metadata) = serde_json::from_str::<TurnMetadataBag>(turn_metadata_header) else {
return;
};
insert_if_valid(
headers,
X_OPENAI_PARENT_CONVERSATION_ID_HEADER,
turn_metadata
.metadata
.get(PARENT_CONVERSATION_ID_METADATA_KEY)
.map(String::as_str),
);
insert_if_valid(
headers,
X_OPENAI_PARENT_MESSAGE_ID_HEADER,
turn_metadata
.metadata
.get(PARENT_MESSAGE_ID_METADATA_KEY)
.map(String::as_str),
);
insert_if_valid(
headers,
X_OPENAI_PARENT_TURN_ID_HEADER,
turn_metadata
.metadata
.get(PARENT_TURN_ID_METADATA_KEY)
.map(String::as_str),
);
}
fn insert_if_valid(headers: &mut HeaderMap, name: &'static str, value: Option<&str>) {
if let Some(value) = value
&& let Ok(header_value) = HeaderValue::from_str(value)
{
headers.insert(name, header_value);
}
}
#[cfg(test)]
#[path = "turn_metadata_tests.rs"]
mod tests;

View File

@@ -88,36 +88,27 @@ fn turn_metadata_state_uses_platform_sandbox_tag() {
}
#[test]
fn extend_known_request_headers_reads_parent_ids_from_turn_metadata() {
let mut headers = http::HeaderMap::new();
let turn_metadata = serde_json::json!({
"turn_id": "turn-a",
"metadata": {
PARENT_CONVERSATION_ID_METADATA_KEY: "conv-123",
PARENT_MESSAGE_ID_METADATA_KEY: "msg-123",
PARENT_TURN_ID_METADATA_KEY: "turn-123",
},
});
let turn_metadata = serde_json::to_string(&turn_metadata).expect("turn metadata json");
fn turn_metadata_state_serializes_custom_metadata() {
let temp_dir = TempDir::new().expect("temp dir");
let cwd = temp_dir.path().to_path_buf();
let sandbox_policy = SandboxPolicy::new_read_only_policy();
let metadata = BTreeMap::from([
("parentConversationId".to_string(), "conv-123".to_string()),
("parentMessageId".to_string(), "msg-123".to_string()),
("parentTurnId".to_string(), "turn-123".to_string()),
]);
extend_known_request_headers(&mut headers, Some(turn_metadata.as_str()));
let state = TurnMetadataState::new(
"session-a".to_string(),
"turn-a".to_string(),
cwd,
&sandbox_policy,
WindowsSandboxLevel::Disabled,
metadata.clone(),
);
assert_eq!(
headers
.get("x-openai-parent-conversation-id")
.and_then(|value| value.to_str().ok()),
Some("conv-123")
);
assert_eq!(
headers
.get("x-openai-parent-message-id")
.and_then(|value| value.to_str().ok()),
Some("msg-123")
);
assert_eq!(
headers
.get("x-openai-parent-turn-id")
.and_then(|value| value.to_str().ok()),
Some("turn-123")
);
let header = state.current_header_value().expect("header");
let json: Value = serde_json::from_str(&header).expect("json");
assert_eq!(json.get("metadata"), Some(&serde_json::json!(metadata)));
}

View File

@@ -549,7 +549,7 @@ async fn responses_stream_includes_turn_metadata_header_for_git_workspace_e2e()
}
#[tokio::test]
async fn responses_stream_includes_parent_headers_from_turn_metadata() {
async fn responses_stream_includes_parent_metadata_in_turn_metadata_header() {
core_test_support::skip_if_no_network!();
let server = responses::start_mock_server().await;
@@ -659,16 +659,22 @@ async fn responses_stream_includes_parent_headers_from_turn_metadata() {
}
let request = request_recorder.single_request();
let turn_metadata_header = request
.header("x-codex-turn-metadata")
.expect("request should include turn metadata");
let turn_metadata: serde_json::Value =
serde_json::from_str(&turn_metadata_header).expect("turn metadata should be valid JSON");
assert_eq!(
request.header("x-openai-parent-conversation-id").as_deref(),
Some("conv-123")
turn_metadata.pointer("/metadata/parentConversationId"),
Some(&json!("conv-123"))
);
assert_eq!(
request.header("x-openai-parent-message-id").as_deref(),
Some("msg-123")
turn_metadata.pointer("/metadata/parentMessageId"),
Some(&json!("msg-123"))
);
assert_eq!(
request.header("x-openai-parent-turn-id").as_deref(),
Some("turn-123")
turn_metadata.pointer("/metadata/parentTurnId"),
Some(&json!("turn-123"))
);
}