mirror of
https://github.com/openai/codex.git
synced 2026-09-13 11:47:17 +00:00
Keep parent request values in turn metadata only
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -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"))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user