llm_agent/
instruction.rs

1use crate::errors::BoxedError;
2use futures::future::BoxFuture;
3
4#[allow(clippy::type_complexity)]
5pub enum InstructionParam<TCtx> {
6    String(String),
7    Func(Box<dyn Fn(&TCtx) -> Result<String, BoxedError> + Send + Sync>),
8    AsyncFunc(Box<dyn Fn(&TCtx) -> BoxFuture<'_, Result<String, BoxedError>> + Send + Sync>),
9}
10
11impl<TCtx> InstructionParam<TCtx> {
12    pub async fn as_string(&self, context: &TCtx) -> Result<String, BoxedError> {
13        match self {
14            Self::String(s) => Ok(s.clone()),
15            Self::Func(f) => f(context),
16            Self::AsyncFunc(f) => f(context).await,
17        }
18    }
19}
20
21impl<TCtx> From<String> for InstructionParam<TCtx> {
22    fn from(value: String) -> Self {
23        Self::String(value)
24    }
25}
26
27impl<TCtx> From<&str> for InstructionParam<TCtx> {
28    fn from(value: &str) -> Self {
29        Self::String(value.to_string())
30    }
31}
32
33impl<TCtx, F> From<F> for InstructionParam<TCtx>
34where
35    F: Fn(&TCtx) -> Result<String, BoxedError> + Send + Sync + 'static,
36    TCtx: Send + Sync + 'static,
37{
38    fn from(value: F) -> Self {
39        Self::Func(Box::new(value))
40    }
41}
42
43pub async fn get_prompt<TCtx>(
44    instructions: &[InstructionParam<TCtx>],
45    context: &TCtx,
46) -> Result<String, BoxedError> {
47    let results =
48        futures::future::join_all(instructions.iter().map(|param| param.as_string(context))).await;
49    Ok(results
50        .into_iter()
51        .collect::<Result<Vec<_>, _>>()?
52        .join("\n"))
53}