actflow_agent_sdk/
types.rs

1//! Type definitions and utilities for the Agent SDK.
2
3use crate::proto;
4use std::collections::HashMap;
5
6/// Execution context for agent.
7#[derive(Debug, Clone)]
8pub struct Context {
9    /// Process ID.
10    pub pid: String,
11    /// Environment variables.
12    pub env: HashMap<String, String>,
13    /// Workflow variables.
14    pub vars: HashMap<String, serde_json::Value>,
15}
16
17impl From<proto::Context> for Context {
18    fn from(ctx: proto::Context) -> Self {
19        Self {
20            pid: ctx.pid,
21            env: ctx.env,
22            vars: ctx
23                .vars
24                .into_iter()
25                .map(|(k, v)| (k, prost_value_to_json(v)))
26                .collect(),
27        }
28    }
29}
30
31impl Default for Context {
32    fn default() -> Self {
33        Self {
34            pid: String::new(),
35            env: HashMap::new(),
36            vars: HashMap::new(),
37        }
38    }
39}
40
41/// Agent inputs as JSON value.
42pub type Inputs = serde_json::Value;
43
44/// Agent execution status.
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub enum ExecutionStatus {
47    Pending,
48    Succeeded,
49    Failed,
50    Exception,
51    Stopped,
52    Paused,
53}
54
55impl From<ExecutionStatus> for proto::NodeExecutionStatus {
56    fn from(status: ExecutionStatus) -> Self {
57        match status {
58            ExecutionStatus::Pending => proto::NodeExecutionStatus::Pending,
59            ExecutionStatus::Succeeded => proto::NodeExecutionStatus::Succeeded,
60            ExecutionStatus::Failed => proto::NodeExecutionStatus::Failed,
61            ExecutionStatus::Exception => proto::NodeExecutionStatus::Exception,
62            ExecutionStatus::Stopped => proto::NodeExecutionStatus::Stopped,
63            ExecutionStatus::Paused => proto::NodeExecutionStatus::Paused,
64        }
65    }
66}
67
68/// Agent output result.
69#[derive(Debug, Clone)]
70pub struct AgentOutput {
71    /// Execution status.
72    pub status: ExecutionStatus,
73    /// Output data.
74    pub outputs: serde_json::Value,
75    /// Error message (if status is Failed).
76    pub error: String,
77    /// Exception message (if status is Exception).
78    pub exception: String,
79}
80
81impl AgentOutput {
82    /// Create a successful output.
83    pub fn success(outputs: serde_json::Value) -> Self {
84        Self {
85            status: ExecutionStatus::Succeeded,
86            outputs,
87            error: String::new(),
88            exception: String::new(),
89        }
90    }
91
92    /// Create a failed output with error message.
93    pub fn failed(error: impl Into<String>) -> Self {
94        Self {
95            status: ExecutionStatus::Failed,
96            outputs: serde_json::Value::Null,
97            error: error.into(),
98            exception: String::new(),
99        }
100    }
101
102    /// Create an exception output.
103    pub fn exception(exception: impl Into<String>) -> Self {
104        Self {
105            status: ExecutionStatus::Exception,
106            outputs: serde_json::Value::Null,
107            error: String::new(),
108            exception: exception.into(),
109        }
110    }
111}
112
113impl From<AgentOutput> for proto::AgentOutput {
114    fn from(output: AgentOutput) -> Self {
115        Self {
116            status: proto::NodeExecutionStatus::from(output.status) as i32,
117            outputs: Some(json_to_prost_value(output.outputs)),
118            error: output.error,
119            exception: output.exception,
120        }
121    }
122}
123
124/// Convert prost_types::Value to serde_json::Value.
125pub(crate) fn prost_value_to_json(value: prost_types::Value) -> serde_json::Value {
126    use prost_types::value::Kind;
127
128    match value.kind {
129        Some(Kind::NullValue(_)) => serde_json::Value::Null,
130        Some(Kind::NumberValue(n)) => serde_json::json!(n),
131        Some(Kind::StringValue(s)) => serde_json::Value::String(s),
132        Some(Kind::BoolValue(b)) => serde_json::Value::Bool(b),
133        Some(Kind::StructValue(s)) => {
134            let map: serde_json::Map<String, serde_json::Value> = s
135                .fields
136                .into_iter()
137                .map(|(k, v)| (k, prost_value_to_json(v)))
138                .collect();
139            serde_json::Value::Object(map)
140        }
141        Some(Kind::ListValue(l)) => {
142            let arr: Vec<serde_json::Value> =
143                l.values.into_iter().map(prost_value_to_json).collect();
144            serde_json::Value::Array(arr)
145        }
146        None => serde_json::Value::Null,
147    }
148}
149
150/// Convert serde_json::Value to prost_types::Value.
151pub(crate) fn json_to_prost_value(value: serde_json::Value) -> prost_types::Value {
152    use prost_types::value::Kind;
153
154    let kind = match value {
155        serde_json::Value::Null => Kind::NullValue(0),
156        serde_json::Value::Bool(b) => Kind::BoolValue(b),
157        serde_json::Value::Number(n) => Kind::NumberValue(n.as_f64().unwrap_or(0.0)),
158        serde_json::Value::String(s) => Kind::StringValue(s),
159        serde_json::Value::Array(arr) => Kind::ListValue(prost_types::ListValue {
160            values: arr.into_iter().map(json_to_prost_value).collect(),
161        }),
162        serde_json::Value::Object(map) => Kind::StructValue(prost_types::Struct {
163            fields: map
164                .into_iter()
165                .map(|(k, v)| (k, json_to_prost_value(v)))
166                .collect(),
167        }),
168    };
169
170    prost_types::Value { kind: Some(kind) }
171}