use crate::{DisplayEntry, DisplayEntryUpdate};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ControlMessage {
Entry { v: u8, entry: DisplayEntry },
Update { v: u8, update: DisplayEntryUpdate },
AgentDestroyed { v: u8, agent_key: String },
}
impl ControlMessage {
pub fn entry(entry: DisplayEntry) -> Self {
Self::Entry { v: 1, entry }
}
pub fn update(update: DisplayEntryUpdate) -> Self {
Self::Update { v: 1, update }
}
pub fn agent_destroyed(agent_key: impl Into<String>) -> Self {
Self::AgentDestroyed {
v: 1,
agent_key: agent_key.into(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HeaderLine {
pub v: u8,
pub tool_use_id: String,
pub stream: String,
pub started_at: String,
}
impl HeaderLine {
pub fn new(tool_use_id: impl Into<String>, stream: impl Into<String>) -> Self {
use std::time::{SystemTime, UNIX_EPOCH};
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
let started_at = format!("@{}", now.as_secs());
Self {
v: 1,
tool_use_id: tool_use_id.into(),
stream: stream.into(),
started_at,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{EntryBody, EntryStatus};
use std::time::SystemTime;
#[test]
fn control_entry_roundtrips() {
let msg = ControlMessage::entry(DisplayEntry {
agent_key: "main".into(),
tool_use_id: "t1".into(),
tool: "bash".into(),
timestamp: SystemTime::UNIX_EPOCH,
headline: "ls".into(),
body: EntryBody::None,
status: EntryStatus::Pending,
});
let s = serde_json::to_string(&msg).unwrap();
assert!(s.contains("\"kind\":\"entry\""));
let parsed: ControlMessage = serde_json::from_str(&s).unwrap();
match parsed {
ControlMessage::Entry { v, entry } => {
assert_eq!(v, 1);
assert_eq!(entry.tool_use_id, "t1");
}
_ => panic!("expected Entry"),
}
}
#[test]
fn header_line_roundtrips() {
let h = HeaderLine::new("t1", "stderr-discarded");
let s = serde_json::to_string(&h).unwrap();
let parsed: HeaderLine = serde_json::from_str(&s).unwrap();
assert_eq!(parsed.tool_use_id, "t1");
assert_eq!(parsed.stream, "stderr-discarded");
}
}