theater 0.3.13

A WebAssembly actor system for AI agents
Documentation
use crate::pack_bridge::{ConversionError, IntoValue, Value};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum WasmEventData {
    WasmCall {
        function_name: String,
        params: Value,
    },
    WasmResult {
        function_name: String,
        state: Value,
        response: Value,
    },
    WasmError {
        function_name: String,
        message: String,
    },
    WasmComponentCreationError {
        error: String,
    },
}

pub struct WasmEvent {
    pub data: WasmEventData,
    pub timestamp: u64,
    pub description: Option<String>,
}

impl IntoValue for WasmEventData {
    fn into_value(self) -> Value {
        match self {
            WasmEventData::WasmCall {
                function_name,
                params,
            } => Value::Variant {
                type_name: String::from("wasm-event-data"),
                case_name: String::from("wasm-call"),
                tag: 0,
                payload: vec![Value::Record {
                    type_name: String::from("wasm-call"),
                    fields: vec![
                        ("function-name".into(), Value::String(function_name)),
                        ("params".into(), params),
                    ],
                }],
            },
            WasmEventData::WasmResult {
                function_name,
                state,
                response,
            } => Value::Variant {
                type_name: String::from("wasm-event-data"),
                case_name: String::from("wasm-result"),
                tag: 1,
                payload: vec![Value::Record {
                    type_name: String::from("wasm-result"),
                    fields: vec![
                        ("function-name".into(), Value::String(function_name)),
                        ("state".into(), state),
                        ("response".into(), response),
                    ],
                }],
            },
            WasmEventData::WasmError {
                function_name,
                message,
            } => Value::Variant {
                type_name: String::from("wasm-event-data"),
                case_name: String::from("wasm-error"),
                tag: 2,
                payload: vec![Value::Record {
                    type_name: String::from("wasm-error"),
                    fields: vec![
                        ("function-name".into(), Value::String(function_name)),
                        ("message".into(), Value::String(message)),
                    ],
                }],
            },
            WasmEventData::WasmComponentCreationError { error } => Value::Variant {
                type_name: String::from("wasm-event-data"),
                case_name: String::from("wasm-component-creation-error"),
                tag: 3,
                payload: vec![Value::Record {
                    type_name: String::from("wasm-component-creation-error"),
                    fields: vec![("error".into(), Value::String(error))],
                }],
            },
        }
    }
}

impl TryFrom<Value> for WasmEventData {
    type Error = ConversionError;

    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::Variant {
                case_name, payload, ..
            } => {
                let record = payload
                    .into_iter()
                    .next()
                    .ok_or_else(|| ConversionError::MissingField("payload".into()))?;
                let fields = match record {
                    Value::Record { fields, .. } => fields,
                    other => return Err(ConversionError::ExpectedRecord(format!("{:?}", other))),
                };

                match case_name.as_str() {
                    "wasm-call" => {
                        let mut function_name = String::new();
                        let mut params = Value::Tuple(vec![]);
                        for (name, val) in fields {
                            match name.as_str() {
                                "function-name" => function_name = String::try_from(val)?,
                                "params" => params = val,
                                _ => {}
                            }
                        }
                        Ok(WasmEventData::WasmCall {
                            function_name,
                            params,
                        })
                    }
                    "wasm-result" => {
                        let mut function_name = String::new();
                        let mut state = Value::Tuple(vec![]);
                        let mut response = Value::Tuple(vec![]);
                        for (name, val) in fields {
                            match name.as_str() {
                                "function-name" => function_name = String::try_from(val)?,
                                "state" => state = val,
                                "response" => response = val,
                                _ => {}
                            }
                        }
                        Ok(WasmEventData::WasmResult {
                            function_name,
                            state,
                            response,
                        })
                    }
                    "wasm-error" => {
                        let mut function_name = String::new();
                        let mut message = String::new();
                        for (name, val) in fields {
                            match name.as_str() {
                                "function-name" => function_name = String::try_from(val)?,
                                "message" => message = String::try_from(val)?,
                                _ => {}
                            }
                        }
                        Ok(WasmEventData::WasmError {
                            function_name,
                            message,
                        })
                    }
                    "wasm-component-creation-error" => {
                        let mut error = String::new();
                        for (name, val) in fields {
                            if name == "error" {
                                error = String::try_from(val)?;
                            }
                        }
                        Ok(WasmEventData::WasmComponentCreationError { error })
                    }
                    other => Err(ConversionError::ExpectedVariant(format!(
                        "unknown wasm-event-data case: {other}"
                    ))),
                }
            }
            other => Err(ConversionError::ExpectedVariant(format!("{:?}", other))),
        }
    }
}