move uuid stamping callsite to earliest boundary

This commit is contained in:
Roy Han
2026-03-19 15:20:34 -07:00
parent 3bce713f76
commit 73559b5898
6 changed files with 108 additions and 15 deletions
+1 -6
View File
@@ -46,12 +46,7 @@ pub struct Prompt {
impl Prompt {
pub(crate) fn get_formatted_input(&self) -> Vec<ResponseItem> {
let mut input: Vec<ResponseItem> = self
.input
.clone()
.into_iter()
.map(ResponseItem::with_generated_metadata_uuid)
.collect();
let mut input = self.input.clone();
// when using the *Freeform* apply_patch tool specifically, tool outputs
// should be structured text, not json. Do NOT reserialize when using
+37 -3
View File
@@ -202,7 +202,7 @@ fn reserializes_shell_outputs_for_function_and_custom_tool_calls() {
}
#[test]
fn formatted_input_generates_message_metadata_uuid() {
fn formatted_input_does_not_generate_message_metadata_uuid_when_disabled() {
let prompt = Prompt {
input: vec![ResponseItem::Message {
id: Some("msg_123".to_string()),
@@ -227,8 +227,42 @@ fn formatted_input_generates_message_metadata_uuid() {
ResponseItem::Message { metadata, .. } => {
let metadata = metadata.as_ref().expect("metadata should be present");
assert_eq!(metadata.user_message_type, Some(UserMessageType::Prompt));
let uuid = metadata.uuid.as_deref().expect("uuid should be present");
uuid::Uuid::parse_str(uuid).expect("uuid should be valid");
assert_eq!(metadata.uuid, None);
}
other => panic!("expected message item, got {other:?}"),
}
}
#[test]
fn formatted_input_preserves_existing_message_metadata_uuid() {
let prompt = Prompt {
input: vec![ResponseItem::Message {
id: Some("msg_123".to_string()),
role: "user".to_string(),
content: vec![ContentItem::InputText {
text: "hello".to_string(),
}],
metadata: Some(ResponseItemMetadata {
user_message_type: Some(UserMessageType::Prompt),
uuid: Some("2585a800-7d93-4f52-8648-d9cb39f413d2".to_string()),
}),
end_turn: None,
phase: None,
}],
..Default::default()
};
let formatted = prompt.get_formatted_input();
assert_eq!(formatted.len(), 1);
match &formatted[0] {
ResponseItem::Message { metadata, .. } => {
let metadata = metadata.as_ref().expect("metadata should be present");
assert_eq!(metadata.user_message_type, Some(UserMessageType::Prompt));
assert_eq!(
metadata.uuid.as_deref(),
Some("2585a800-7d93-4f52-8648-d9cb39f413d2")
);
}
other => panic!("expected message item, got {other:?}"),
}
+25 -6
View File
@@ -3259,12 +3259,9 @@ impl Session {
turn_context: &TurnContext,
items: &[ResponseItem],
) {
let items: Vec<ResponseItem> = items
.iter()
.cloned()
.map(ResponseItem::with_generated_metadata_uuid)
.collect();
self.record_into_history(&items, turn_context).await;
let items = self.prepare_history_items(items);
self.record_into_history_prepared(&items, turn_context)
.await;
self.persist_rollout_response_items(&items).await;
self.send_raw_response_items(turn_context, &items).await;
}
@@ -3274,6 +3271,28 @@ impl Session {
&self,
items: &[ResponseItem],
turn_context: &TurnContext,
) {
let items = self.prepare_history_items(items);
self.record_into_history_prepared(&items, turn_context)
.await;
}
fn prepare_history_items(&self, items: &[ResponseItem]) -> Vec<ResponseItem> {
if self.enabled(Feature::ItemMetadata) {
items
.iter()
.cloned()
.map(ResponseItem::with_generated_metadata_uuid)
.collect()
} else {
items.to_vec()
}
}
async fn record_into_history_prepared(
&self,
items: &[ResponseItem],
turn_context: &TurnContext,
) {
let mut state = self.state.lock().await;
state.record_items(items.iter(), turn_context.truncation_policy);
+31
View File
@@ -4386,6 +4386,37 @@ async fn steer_input_returns_active_turn_id() {
assert!(sess.has_pending_input().await);
}
#[tokio::test]
async fn record_into_history_generates_message_metadata_uuid_when_item_metadata_enabled() {
let (mut sess, tc) = make_session_and_context().await;
let _ = sess.features.enable(crate::features::Feature::ItemMetadata);
let item = ResponseItem::Message {
id: Some("msg_123".to_string()),
role: "user".to_string(),
content: vec![ContentItem::InputText {
text: "hello".to_string(),
}],
metadata: None,
end_turn: None,
phase: None,
};
sess.record_into_history(std::slice::from_ref(&item), &tc)
.await;
let history = sess.state.lock().await.clone_history();
let [ResponseItem::Message { metadata, .. }] = history.raw_items() else {
panic!("expected a single message item in history");
};
let uuid = metadata
.as_ref()
.and_then(|metadata| metadata.uuid.as_deref())
.expect("uuid should be generated when item metadata is enabled");
uuid::Uuid::parse_str(uuid).expect("uuid should be valid");
}
#[tokio::test]
async fn prepend_pending_input_keeps_older_tail_ahead_of_newer_input() {
let (sess, tc, _rx) = make_session_and_context_with_rx().await;
+8
View File
@@ -172,6 +172,8 @@ pub enum Feature {
ToolCallMcpElicitation,
/// Enable personality selection in the TUI.
Personality,
/// Emit item-level metadata such as user message type and generated UUIDs.
ItemMetadata,
/// Enable native artifact tools.
Artifact,
/// Enable Fast mode selection in the TUI and request layer.
@@ -805,6 +807,12 @@ pub const FEATURES: &[FeatureSpec] = &[
stage: Stage::Stable,
default_enabled: true,
},
FeatureSpec {
id: Feature::ItemMetadata,
key: "item_metadata",
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::Artifact,
key: "artifact",
+6
View File
@@ -136,6 +136,12 @@ fn image_detail_original_feature_is_under_development() {
assert_eq!(Feature::ImageDetailOriginal.default_enabled(), false);
}
#[test]
fn item_metadata_is_under_development_and_disabled_by_default() {
assert_eq!(Feature::ItemMetadata.stage(), Stage::UnderDevelopment);
assert_eq!(Feature::ItemMetadata.default_enabled(), false);
}
#[test]
fn collab_is_legacy_alias_for_multi_agent() {
assert_eq!(feature_for_key("multi_agent"), Some(Feature::Collab));