llm-agent 0.3.0

The agent library to build LLM applications that work with any LLM providers.
Documentation
use crate::errors::BoxedError;
use futures::future::BoxFuture;

#[allow(clippy::type_complexity)]
pub enum InstructionParam<TCtx> {
    String(String),
    Func(Box<dyn Fn(&TCtx) -> Result<String, BoxedError> + Send + Sync>),
    AsyncFunc(Box<dyn Fn(&TCtx) -> BoxFuture<'_, Result<String, BoxedError>> + Send + Sync>),
}

impl<TCtx> InstructionParam<TCtx> {
    pub async fn as_string(&self, context: &TCtx) -> Result<String, BoxedError> {
        match self {
            Self::String(s) => Ok(s.clone()),
            Self::Func(f) => f(context),
            Self::AsyncFunc(f) => f(context).await,
        }
    }
}

impl<TCtx> From<String> for InstructionParam<TCtx> {
    fn from(value: String) -> Self {
        Self::String(value)
    }
}

impl<TCtx> From<&str> for InstructionParam<TCtx> {
    fn from(value: &str) -> Self {
        Self::String(value.to_string())
    }
}

impl<TCtx, F> From<F> for InstructionParam<TCtx>
where
    F: Fn(&TCtx) -> Result<String, BoxedError> + Send + Sync + 'static,
    TCtx: Send + Sync + 'static,
{
    fn from(value: F) -> Self {
        Self::Func(Box::new(value))
    }
}

pub async fn get_prompt<TCtx>(
    instructions: &[InstructionParam<TCtx>],
    context: &TCtx,
) -> Result<String, BoxedError> {
    let results =
        futures::future::join_all(instructions.iter().map(|param| param.as_string(context))).await;
    Ok(results
        .into_iter()
        .collect::<Result<Vec<_>, _>>()?
        .join("\n"))
}