use std::{pin::Pin, sync::Arc};
use async_trait::async_trait;
use futures::Stream;
use crate::{
language_models::TokenUsage,
prompt::PromptArgs,
schemas::agent::{AgentAction, AgentEvent, AgentFinish},
tools::Tool,
};
use super::AgentError;
#[derive(Debug)]
#[non_exhaustive]
pub enum PlanEvent {
Text(String),
Usage(TokenUsage),
Done(AgentEvent),
}
pub type PlanEventStream<'a> =
Pin<Box<dyn Stream<Item = Result<PlanEvent, AgentError>> + Send + 'a>>;
pub(crate) fn box_plan_events<'a, S>(stream: S) -> PlanEventStream<'a>
where
S: Stream<Item = Result<PlanEvent, AgentError>> + Send + 'a,
{
Box::pin(stream)
}
#[async_trait]
pub trait Agent: Send + Sync {
async fn plan(
&self,
intermediate_steps: &[(AgentAction, String)],
inputs: PromptArgs,
) -> Result<AgentEvent, AgentError>;
fn get_tools(&self) -> Vec<Arc<dyn Tool>>;
async fn plan_with_usage(
&self,
intermediate_steps: &[(AgentAction, String)],
inputs: PromptArgs,
) -> Result<(AgentEvent, Option<TokenUsage>), AgentError> {
Ok((self.plan(intermediate_steps, inputs).await?, None))
}
fn plan_stream<'a>(
&'a self,
intermediate_steps: &'a [(AgentAction, String)],
inputs: PromptArgs,
) -> PlanEventStream<'a> {
box_plan_events(async_stream::try_stream! {
let (event, usage) = self.plan_with_usage(intermediate_steps, inputs).await?;
if let AgentEvent::Finish(AgentFinish { output }) = &event {
if !output.is_empty() {
yield PlanEvent::Text(output.clone());
}
}
if let Some(usage) = usage {
yield PlanEvent::Usage(usage);
}
yield PlanEvent::Done(event);
})
}
}