use serde::{Deserialize, Serialize};
pub const PROTOCOL_VERSION: u32 = 2;
pub const MIN_PROTOCOL_VERSION: u32 = 1;
pub const SERVER_CAPABILITIES: &[&str] = &[
"state_diffs",
"batch_actions",
"screenshot",
"ws_transport",
"protocol_v2",
];
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AgentRequest {
#[serde(rename = "query_ontology")]
QueryOntology {
#[serde(default)]
query: Option<String>,
#[serde(default)]
role: Option<String>,
},
#[serde(rename = "get_schema")]
GetSchema { widget_type: String },
#[serde(rename = "get_tree")]
GetTree,
#[serde(rename = "get_state")]
GetState { agent_id: String },
#[serde(rename = "execute_action")]
ExecuteAction {
agent_id: String,
action: String,
#[serde(default)]
params: serde_json::Value,
},
#[serde(rename = "inject_event")]
InjectEvent { event: InjectedEvent },
#[serde(rename = "subscribe")]
Subscribe { events: Vec<String> },
#[serde(rename = "unsubscribe")]
Unsubscribe { events: Vec<String> },
#[serde(rename = "ping")]
Ping,
#[serde(rename = "quit")]
Quit,
#[serde(rename = "screenshot")]
Screenshot {
#[serde(default = "default_format")]
format: String,
},
#[serde(rename = "batch_actions")]
BatchActions { actions: Vec<BatchActionEntry> },
#[serde(rename = "negotiate")]
Negotiate {
client_version: u32,
#[serde(default)]
capabilities: Vec<String>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchActionEntry {
pub agent_id: String,
pub action: String,
#[serde(default)]
pub params: serde_json::Value,
}
fn default_format() -> String {
"png".into()
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind")]
pub enum InjectedEvent {
#[serde(rename = "key")]
Key {
code: String,
#[serde(default)]
modifiers: Vec<String>,
},
#[serde(rename = "mouse_click")]
MouseClick { x: f32, y: f32, button: String },
#[serde(rename = "mouse_move")]
MouseMove { x: f32, y: f32 },
#[serde(rename = "mouse_scroll")]
MouseScroll {
x: f32,
y: f32,
delta_x: f32,
delta_y: f32,
},
#[serde(rename = "text_input")]
TextInput { text: String },
#[serde(rename = "resize")]
Resize { width: f32, height: f32 },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentResponse {
pub success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
impl AgentResponse {
pub fn ok(data: serde_json::Value) -> Self {
Self {
success: true,
id: None,
data: Some(data),
error: None,
}
}
pub fn err(message: impl Into<String>) -> Self {
Self {
success: false,
id: None,
data: None,
error: Some(message.into()),
}
}
pub fn with_id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AgentEvent {
#[serde(rename = "state_changed")]
StateChanged {
agent_id: String,
state: serde_json::Value,
},
#[serde(rename = "action_result")]
ActionResult {
agent_id: String,
action: String,
result: serde_json::Value,
},
#[serde(rename = "render_update")]
RenderUpdate { tree: serde_json::Value },
#[serde(rename = "app_quit")]
AppQuit,
#[serde(rename = "pong")]
Pong,
#[serde(rename = "error")]
Error { message: String },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RequestEnvelope {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub request: AgentRequest,
}