mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat(core): store turn_id on ResponseItem metadata (#28360)
## Description This PR is a followup to https://github.com/openai/codex/pull/28355 and starts assigning `internal_chat_message_metadata_passthrough.turn_id` to durable Responses API items created during a turn. The goal is that those items keep the `turn_id` that introduced them when Codex resends stateless HTTP context, reconstructs history for resume/fork paths, or reuses websocket response state. ## What changed - Set `internal_chat_message_metadata_passthrough.turn_id` when missing as response items enter durable history, initial/replacement history, inter-agent communication history, and local compaction summaries. - Preserve existing item turn IDs instead of overwriting them during persistence, resume reconstruction, compaction, forked history, and websocket incremental reuse. - Keep `compaction_trigger` fieldless because it is a request control, not a durable response item. - Update focused history/request assertions and fixtures for stateless requests, websocket incrementals, compaction, thread injection, prompt debug, and related CI coverage.
This commit is contained in:
@@ -266,7 +266,7 @@ fn format_request_body_snapshot(
|
||||
request: &ResponsesRequest,
|
||||
options: &ContextSnapshotOptions,
|
||||
) -> String {
|
||||
let mut body = request.body_json();
|
||||
let mut body = crate::responses::strip_metadata_from_json(request.body_json());
|
||||
canonicalize_json_snapshot_value(&mut body, options);
|
||||
serde_json::to_string_pretty(&body).expect("request body should serialize")
|
||||
}
|
||||
|
||||
@@ -98,6 +98,35 @@ fn decode_body_bytes(body: &[u8], content_encoding: Option<&str>) -> Vec<u8> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a response item without internal transport metadata for semantic assertions.
|
||||
pub fn strip_metadata(mut item: ResponseItem) -> ResponseItem {
|
||||
item.clear_internal_chat_message_metadata_passthrough();
|
||||
item
|
||||
}
|
||||
|
||||
/// Returns response items without internal transport metadata for semantic assertions.
|
||||
pub fn strip_metadata_from_items(items: &[ResponseItem]) -> Vec<ResponseItem> {
|
||||
items.iter().cloned().map(strip_metadata).collect()
|
||||
}
|
||||
|
||||
/// Returns JSON without internal transport metadata for semantic assertions.
|
||||
pub fn strip_metadata_from_json(value: Value) -> Value {
|
||||
match value {
|
||||
Value::Array(values) => {
|
||||
Value::Array(values.into_iter().map(strip_metadata_from_json).collect())
|
||||
}
|
||||
Value::Object(mut map) => {
|
||||
map.remove("internal_chat_message_metadata_passthrough");
|
||||
Value::Object(
|
||||
map.into_iter()
|
||||
.map(|(key, value)| (key, strip_metadata_from_json(value)))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
value => value,
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponsesRequest {
|
||||
pub fn body_json(&self) -> Value {
|
||||
let body = decode_body_bytes(
|
||||
@@ -1092,11 +1121,17 @@ pub async fn mount_compact_user_history_with_summary_sequence(
|
||||
)
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
// Append a synthetic compaction item as the newest item.
|
||||
output.push(serde_json::json!({
|
||||
let compaction_turn_id = body_json["client_metadata"]["turn_id"].as_str();
|
||||
// Match Responses API: generated compaction items inherit the compact request turn.
|
||||
let mut compaction_item = serde_json::json!({
|
||||
"type": "compaction",
|
||||
"encrypted_content": summary_text,
|
||||
}));
|
||||
});
|
||||
if let Some(turn_id) = compaction_turn_id {
|
||||
compaction_item["internal_chat_message_metadata_passthrough"] =
|
||||
serde_json::json!({ "turn_id": turn_id });
|
||||
}
|
||||
output.push(compaction_item);
|
||||
ResponseTemplate::new(200)
|
||||
.insert_header("content-type", "application/json")
|
||||
.set_body_json(serde_json::json!({ "output": output }))
|
||||
|
||||
Reference in New Issue
Block a user