use a2a_protocol_types::events::StreamResponse;
pub(super) fn stamp_status(event: &mut StreamResponse) {
let status = match event {
StreamResponse::StatusUpdate(update) => &mut update.status,
StreamResponse::Task(task) => &mut task.status,
_ => return,
};
if status.timestamp.is_none() {
status.timestamp = Some(a2a_protocol_types::utc_now_iso8601());
}
}
#[cfg(test)]
mod tests {
use a2a_protocol_types::events::{StreamResponse, TaskStatusUpdateEvent};
use a2a_protocol_types::task::{ContextId, Task, TaskId, TaskState, TaskStatus};
use super::stamp_status;
fn update(status: TaskStatus) -> StreamResponse {
StreamResponse::StatusUpdate(TaskStatusUpdateEvent {
task_id: TaskId::new("t"),
context_id: ContextId::new("c"),
status,
metadata: None,
})
}
fn timestamp(event: &StreamResponse) -> Option<&str> {
match event {
StreamResponse::StatusUpdate(u) => u.status.timestamp.as_deref(),
StreamResponse::Task(t) => t.status.timestamp.as_deref(),
_ => None,
}
}
#[test]
fn a_status_without_a_timestamp_is_stamped_in_iso_8601_utc() {
let mut event = update(TaskStatus::new(TaskState::Working));
stamp_status(&mut event);
let ts = timestamp(&event).expect("stamped");
assert!(ts.ends_with('Z') && ts.contains('T'), "{ts}");
assert!(
a2a_protocol_types::parse_iso8601_to_unix_millis(ts).is_some(),
"{ts} parses"
);
}
#[test]
fn a_timestamp_the_executor_set_is_kept() {
let mut status = TaskStatus::new(TaskState::Completed);
status.timestamp = Some("2026-01-02T03:04:05Z".into());
let mut event = update(status);
stamp_status(&mut event);
assert_eq!(timestamp(&event), Some("2026-01-02T03:04:05Z"));
}
#[test]
fn a_task_snapshot_without_a_timestamp_is_stamped() {
let mut event = StreamResponse::Task(Task {
id: TaskId::new("t"),
context_id: ContextId::new("c"),
status: TaskStatus::new(TaskState::Submitted),
history: None,
artifacts: None,
metadata: None,
});
stamp_status(&mut event);
let ts = timestamp(&event).expect("stamped");
assert!(
a2a_protocol_types::parse_iso8601_to_unix_millis(ts).is_some(),
"{ts} parses"
);
}
}