Stamp conversation history items with creation times (#38272)

## What changed

- Add fractional Unix creation times to locally authored user, developer, agent, and tool-output items when they enter durable conversation history.
- Preserve any creation time already supplied with an item across subsequent requests, remote compaction, and resumed history.

## Testing

- Cover timestamp assignment and preservation in session, client, tool, agent-spawn, and remote-compaction tests.

GitOrigin-RevId: 431d1770b9746005c808bc0a43953845166d68ad
This commit is contained in:
ashwinnathan-openai
2026-08-12 23:04:42 +00:00
committed by copyberry
parent 842fae26c9
commit 361fe2d202
10 changed files with 196 additions and 22 deletions
+49 -1
View File
@@ -790,6 +790,11 @@ pub struct InternalChatMessageMetadataPassthrough {
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
pub turn_id: Option<String>,
/// Message creation time in fractional Unix seconds.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[schemars(skip)]
#[ts(skip)]
pub create_time: Option<serde_json::Number>,
/// Warehouse-only Responses metadata, not part of the public app-server protocol.
#[serde(default, skip_deserializing, skip_serializing_if = "Option::is_none")]
#[schemars(skip)]
@@ -1133,6 +1138,39 @@ impl ResponseItem {
InternalChatMessageMetadataPassthrough::set_turn_id_if_missing(metadata, turn_id);
}
/// Stamps a harness-authored durable item without replacing its creation time.
pub fn set_create_time_if_missing(&mut self, create_time: serde_json::Number) {
let metadata = match self {
Self::Message {
role,
internal_chat_message_metadata_passthrough: metadata,
..
} if matches!(role.as_str(), "user" | "developer") => metadata,
Self::AgentMessage {
internal_chat_message_metadata_passthrough: metadata,
..
}
| Self::FunctionCallOutput {
internal_chat_message_metadata_passthrough: metadata,
..
}
| Self::CustomToolCallOutput {
internal_chat_message_metadata_passthrough: metadata,
..
}
| Self::ToolSearchOutput {
internal_chat_message_metadata_passthrough: metadata,
..
} => metadata,
_ => return,
};
metadata
.get_or_insert_default()
.create_time
.get_or_insert(create_time);
}
/// Removes internal chat message metadata passthrough before sending to a provider that does
/// not accept it.
pub fn clear_internal_chat_message_metadata_passthrough(&mut self) {
@@ -2357,9 +2395,19 @@ mod tests {
let mut missing_turn_id = response_item_with_passthrough_metadata(
/*internal_chat_message_metadata_passthrough*/ None,
);
let create_time = serde_json::Number::from(123);
missing_turn_id.set_create_time_if_missing(create_time.clone());
missing_turn_id.set_turn_id_if_missing("");
missing_turn_id.set_turn_id_if_missing("turn-1");
assert_eq!(missing_turn_id.turn_id(), Some("turn-1"));
missing_turn_id.set_create_time_if_missing(serde_json::Number::from(456));
assert_eq!(
missing_turn_id.executed_tool_call_metadata(),
Some(&InternalChatMessageMetadataPassthrough {
turn_id: Some("turn-1".to_string()),
create_time: Some(create_time),
..Default::default()
})
);
let mut other = ResponseItem::Other;
other.set_turn_id_if_missing("turn-1");