lashlang 0.1.0-alpha.1

Lashlang: compact CodeAct language for model-authored REPL blocks in the lash agent runtime.
Documentation
use super::{Record, Value};
use futures_util::future::join_all;
use std::future::Future;
use thiserror::Error;

#[derive(Clone, Debug)]
pub struct ToolHostCall {
    pub name: String,
    pub args: Record,
}

pub trait ToolHost: Sync {
    fn call(
        &self,
        name: String,
        args: Record,
    ) -> impl Future<Output = Result<Value, ToolHostError>> + Send;

    fn call_batch(
        &self,
        calls: Vec<ToolHostCall>,
    ) -> impl Future<Output = Vec<Result<Value, ToolHostError>>> + Send {
        async move {
            join_all(
                calls
                    .into_iter()
                    .map(|call| self.call(call.name, call.args)),
            )
            .await
        }
    }

    fn start_call(
        &self,
        _name: String,
        _args: Record,
    ) -> impl Future<Output = Result<Value, ToolHostError>> + Send {
        async { Err(ToolHostError::new("async tool starts are unavailable")) }
    }

    fn await_handle(
        &self,
        _handle: Value,
    ) -> impl Future<Output = Result<Value, ToolHostError>> + Send {
        async { Err(ToolHostError::new("async tool handles are unavailable")) }
    }

    fn cancel_handle(
        &self,
        _handle: Value,
    ) -> impl Future<Output = Result<Value, ToolHostError>> + Send {
        async { Err(ToolHostError::new("async tool handles are unavailable")) }
    }

    fn print(&self, _value: Value) -> impl Future<Output = Result<(), ToolHostError>> + Send {
        async { Ok(()) }
    }

    fn yield_now(&self) -> impl Future<Output = ()> + Send {
        async {}
    }
}

#[derive(Clone, Debug, Error, PartialEq, Eq)]
#[error("{message}")]
pub struct ToolHostError {
    message: String,
}

impl ToolHostError {
    pub fn new(message: impl Into<String>) -> Self {
        Self {
            message: message.into(),
        }
    }
}