orchestral-runtime 0.2.0

Thread Runtime with concurrency, interruption, scheduling, LLM planners, actions, and API for Orchestral
Documentation
use async_trait::async_trait;
use serde_json::{json, Value};

use orchestral_core::action::{Action, ActionContext, ActionInput, ActionMeta, ActionResult};
use orchestral_core::config::ActionSpec;

use super::support::config_string;

pub(super) struct EchoAction {
    name: String,
    description: String,
    prefix: String,
}

impl EchoAction {
    pub(super) fn from_spec(spec: &ActionSpec) -> Self {
        let prefix = config_string(&spec.config, "prefix").unwrap_or_default();
        Self {
            name: spec.name.clone(),
            description: spec.description_or("Echoes the input back as output"),
            prefix,
        }
    }
}

#[async_trait]
impl Action for EchoAction {
    fn name(&self) -> &str {
        &self.name
    }

    fn description(&self) -> &str {
        &self.description
    }

    fn metadata(&self) -> ActionMeta {
        ActionMeta::new(self.name(), self.description())
            .with_category("utility")
            .with_capability("pure")
            .with_input_kinds(["text"])
            .with_output_kinds(["text"])
            .with_input_schema(json!({
                "type": "object",
                "properties": {
                    "message": {
                        "type": "string",
                        "description": "Text to echo back."
                    }
                },
                "required": ["message"]
            }))
            .with_output_schema(json!({
                "type": "object",
                "properties": {
                    "result": {
                        "type": "string",
                        "description": "Echoed text result."
                    }
                },
                "required": ["result"]
            }))
    }

    async fn run(&self, input: ActionInput, _ctx: ActionContext) -> ActionResult {
        let message = input
            .params
            .get("message")
            .and_then(|v| v.as_str())
            .unwrap_or("No message provided");
        let result = format!("{}{}", self.prefix, message);
        ActionResult::success_with_one("result", Value::String(result))
    }
}