use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum PointerType { Move, Down, Up, Click, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum PointerButton { Left, Right, Middle, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum ScrollDirection { Up, Down, } /// Canonical actions the control plane understands. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "lowercase")] pub enum ComputerAction { Pointer { x: u32, y: u32, #[serde(rename = "type")] pointer_type: PointerType, #[serde(default)] button: Option, }, Clipboard { text: String, }, Key { key: String, #[serde(default)] modifiers: Option>, }, Scroll { direction: ScrollDirection, #[serde(default)] amount: Option, }, Wait { ms: u32, }, Open { path: String, }, Launch { application: String, #[serde(default)] uri: Option, }, Focus { title: String, }, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct CursorPosition { pub x: i32, pub y: i32, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ActiveWindow { pub id: String, pub title: Option, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ComputerObservation { pub frame_id: String, pub captured_at: String, pub mime_type: String, #[serde(with = "serde_bytes_opt")] pub image: Vec, pub width: u32, pub height: u32, pub cursor: Option, pub active_window: Option, } mod serde_bytes_opt { use base64::engine::general_purpose::STANDARD; use base64::Engine; use serde::{Deserialize, Deserializer, Serializer}; pub fn serialize(bytes: &[u8], serializer: S) -> Result { serializer.serialize_str(&STANDARD.encode(bytes)) } pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { let text = String::deserialize(deserializer)?; STANDARD.decode(text).map_err(serde::de::Error::custom) } }