use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Deserialize)]
pub struct RuntimeInitializeParams {
pub namespace: String,
#[serde(default)]
pub options: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RuntimeInitializeResult {
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub env: HashMap<String, String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub workspace_root: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ExecRequest {
pub cmd: Vec<String>,
#[serde(default)]
pub env: HashMap<String, String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub working_dir: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ExecResult {
pub process_id: String,
pub stdio_addr: String,
pub stderr_addr: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RuntimeHealthStatus {
pub status: RuntimeHealth,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeHealth {
Healthy,
Degraded,
Unhealthy,
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[rstest]
fn when_init_params_deserialized_then_fields_present() {
let json = r#"{"namespace": "anyclaw-prod", "options": {"image": "ubuntu:22.04"}}"#;
let params: RuntimeInitializeParams = serde_json::from_str(json).unwrap();
assert_eq!(params.namespace, "anyclaw-prod");
assert_eq!(
params.options.get("image").and_then(|v| v.as_str()),
Some("ubuntu:22.04")
);
}
#[rstest]
fn when_exec_request_deserialized_then_cmd_present() {
let json = r#"{"cmd": ["/usr/bin/agent", "--stdio"], "env": {"FOO": "bar"}}"#;
let req: ExecRequest = serde_json::from_str(json).unwrap();
assert_eq!(req.cmd, vec!["/usr/bin/agent", "--stdio"]);
assert_eq!(req.env.get("FOO").map(String::as_str), Some("bar"));
}
#[rstest]
fn when_exec_result_serialized_then_contains_addrs() {
let result = ExecResult {
process_id: "proc-1".into(),
stdio_addr: "/tmp/anyclaw/proc-1.sock".into(),
stderr_addr: "/tmp/anyclaw/proc-1-err.sock".into(),
};
let json = serde_json::to_value(&result).unwrap();
assert_eq!(json["process_id"], "proc-1");
assert_eq!(json["stdio_addr"], "/tmp/anyclaw/proc-1.sock");
}
#[rstest]
fn when_health_status_serialized_then_snake_case() {
let status = RuntimeHealthStatus {
status: RuntimeHealth::Healthy,
message: None,
};
let json = serde_json::to_value(&status).unwrap();
assert_eq!(json["status"], "healthy");
}
}