agentmux_srv\drone\executor\blocks/
variables.rs

1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Variables block — declares drone-scope vars. The block's
5//! `data.entries` is a list of `{name, value}` pairs; each value is
6//! `{{}}`-resolved against the current scope and written as the var.
7//!
8//! Output: `{ "vars": { name: value, ... } }` so downstream blocks can
9//! read them via `{{var.name}}` OR `{{<this_block_id>.vars.name}}`.
10
11use serde_json::{json, Value};
12
13use crate::drone::data_flow::ExecutionScope;
14use crate::drone::types::FlowNode;
15
16pub async fn run(node: &FlowNode, scope: &mut ExecutionScope) -> Result<Value, String> {
17    let entries = node
18        .data
19        .get("entries")
20        .and_then(|v| v.as_array())
21        .cloned()
22        .unwrap_or_default();
23    let mut written = serde_json::Map::new();
24    for e in entries {
25        let name = e
26            .get("name")
27            .and_then(|v| v.as_str())
28            .ok_or_else(|| "variables entry missing `name`".to_string())?;
29        let raw = e.get("value").cloned().unwrap_or(Value::Null);
30        let resolved = match raw {
31            Value::String(s) => Value::String(scope.resolve(&s)),
32            other => other,
33        };
34        scope.vars.insert(name.to_string(), resolved.clone());
35        written.insert(name.to_string(), resolved);
36    }
37    Ok(json!({ "vars": written }))
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43    use crate::drone::types::NodePosition;
44
45    #[tokio::test]
46    async fn writes_string_var_with_resolution() {
47        let node = FlowNode {
48            id: "v1".to_string(),
49            position: NodePosition::default(),
50            data: json!({
51                "kind": "variables",
52                "entries": [
53                    { "name": "greeting", "value": "hi" }
54                ]
55            }),
56            node_type: String::new(),
57        };
58        let mut scope = ExecutionScope::new();
59        let out = run(&node, &mut scope).await.unwrap();
60        assert_eq!(scope.vars.get("greeting").unwrap(), &json!("hi"));
61        assert_eq!(out["vars"]["greeting"], json!("hi"));
62    }
63}