Skip to main content

anyclaw_sdk_runtime/
types.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4/// Parameters sent to a runtime during the `initialize` handshake.
5#[derive(Debug, Clone, Deserialize)]
6pub struct RuntimeInitializeParams {
7    /// Deployment namespace for scoping resources (networks, volumes).
8    pub namespace: String,
9    /// Runtime-specific configuration from `anyclaw.yaml`.
10    #[serde(default)]
11    pub options: HashMap<String, serde_json::Value>,
12}
13
14/// Result returned by a runtime after successful initialization.
15#[derive(Debug, Clone, Serialize)]
16pub struct RuntimeInitializeResult {
17    /// Environment variables that should be set on exec'd processes.
18    /// E.g., `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`.
19    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
20    pub env: HashMap<String, String>,
21    /// Workspace root path inside the runtime environment.
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub workspace_root: Option<String>,
24}
25
26/// Request to execute a process inside the runtime environment.
27#[derive(Debug, Clone, Deserialize)]
28pub struct ExecRequest {
29    /// Command and arguments to execute.
30    pub cmd: Vec<String>,
31    /// Environment variables to set on the process (merged with runtime env).
32    #[serde(default)]
33    pub env: HashMap<String, String>,
34    /// Working directory inside the environment.
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub working_dir: Option<String>,
37}
38
39/// Result of starting a process inside the runtime.
40#[derive(Debug, Clone, Serialize)]
41pub struct ExecResult {
42    /// Opaque process identifier (runtime-specific).
43    pub process_id: String,
44    /// Unix socket path for bidirectional stdio (stdin + stdout).
45    /// The supervisor connects to this socket to communicate with the process.
46    pub stdio_addr: String,
47    /// Unix socket path for stderr stream.
48    pub stderr_addr: String,
49}
50
51/// Health status reported by a runtime.
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct RuntimeHealthStatus {
54    /// Current health state.
55    pub status: RuntimeHealth,
56    /// Optional detail message.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub message: Option<String>,
59}
60
61/// Possible health states for a runtime.
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
63#[serde(rename_all = "snake_case")]
64pub enum RuntimeHealth {
65    /// Runtime environment is fully operational.
66    Healthy,
67    /// Runtime is operational but experiencing issues.
68    Degraded,
69    /// Runtime is not operational.
70    Unhealthy,
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use rstest::rstest;
77
78    #[rstest]
79    fn when_init_params_deserialized_then_fields_present() {
80        let json = r#"{"namespace": "anyclaw-prod", "options": {"image": "ubuntu:22.04"}}"#;
81        let params: RuntimeInitializeParams = serde_json::from_str(json).unwrap();
82        assert_eq!(params.namespace, "anyclaw-prod");
83        assert_eq!(
84            params.options.get("image").and_then(|v| v.as_str()),
85            Some("ubuntu:22.04")
86        );
87    }
88
89    #[rstest]
90    fn when_exec_request_deserialized_then_cmd_present() {
91        let json = r#"{"cmd": ["/usr/bin/agent", "--stdio"], "env": {"FOO": "bar"}}"#;
92        let req: ExecRequest = serde_json::from_str(json).unwrap();
93        assert_eq!(req.cmd, vec!["/usr/bin/agent", "--stdio"]);
94        assert_eq!(req.env.get("FOO").map(String::as_str), Some("bar"));
95    }
96
97    #[rstest]
98    fn when_exec_result_serialized_then_contains_addrs() {
99        let result = ExecResult {
100            process_id: "proc-1".into(),
101            stdio_addr: "/tmp/anyclaw/proc-1.sock".into(),
102            stderr_addr: "/tmp/anyclaw/proc-1-err.sock".into(),
103        };
104        let json = serde_json::to_value(&result).unwrap();
105        assert_eq!(json["process_id"], "proc-1");
106        assert_eq!(json["stdio_addr"], "/tmp/anyclaw/proc-1.sock");
107    }
108
109    #[rstest]
110    fn when_health_status_serialized_then_snake_case() {
111        let status = RuntimeHealthStatus {
112            status: RuntimeHealth::Healthy,
113            message: None,
114        };
115        let json = serde_json::to_value(&status).unwrap();
116        assert_eq!(json["status"], "healthy");
117    }
118}