use anyhow::Result;
use async_trait::async_trait;
use dyn_clone::DynClone;
use futures_util::Stream;
use std::{borrow::Cow, pin::Pin, sync::Arc};
use crate::AgentContext;
use super::{
ToolCall, ToolOutput, ToolSpec,
chat_completion_request::ChatCompletionRequest,
chat_completion_response::ChatCompletionResponse,
errors::{LanguageModelError, ToolError},
};
pub type ChatCompletionStream =
Pin<Box<dyn Stream<Item = Result<ChatCompletionResponse, LanguageModelError>> + Send>>;
#[async_trait]
pub trait ChatCompletion: Send + Sync + DynClone {
async fn complete(
&self,
request: &ChatCompletionRequest<'_>,
) -> Result<ChatCompletionResponse, LanguageModelError>;
async fn complete_stream(&self, request: &ChatCompletionRequest<'_>) -> ChatCompletionStream {
Box::pin(tokio_stream::iter(vec![self.complete(request).await]))
}
}
#[async_trait]
impl ChatCompletion for Box<dyn ChatCompletion> {
async fn complete(
&self,
request: &ChatCompletionRequest<'_>,
) -> Result<ChatCompletionResponse, LanguageModelError> {
(**self).complete(request).await
}
async fn complete_stream(&self, request: &ChatCompletionRequest<'_>) -> ChatCompletionStream {
(**self).complete_stream(request).await
}
}
#[async_trait]
impl ChatCompletion for &dyn ChatCompletion {
async fn complete(
&self,
request: &ChatCompletionRequest<'_>,
) -> Result<ChatCompletionResponse, LanguageModelError> {
(**self).complete(request).await
}
async fn complete_stream(&self, request: &ChatCompletionRequest<'_>) -> ChatCompletionStream {
(**self).complete_stream(request).await
}
}
#[async_trait]
impl<T> ChatCompletion for &T
where
T: ChatCompletion + Clone + 'static,
{
async fn complete(
&self,
request: &ChatCompletionRequest<'_>,
) -> Result<ChatCompletionResponse, LanguageModelError> {
(**self).complete(request).await
}
async fn complete_stream(&self, request: &ChatCompletionRequest<'_>) -> ChatCompletionStream {
(**self).complete_stream(request).await
}
}
impl<LLM> From<&LLM> for Box<dyn ChatCompletion>
where
LLM: ChatCompletion + Clone + 'static,
{
fn from(llm: &LLM) -> Self {
Box::new(llm.clone()) as Box<dyn ChatCompletion>
}
}
dyn_clone::clone_trait_object!(ChatCompletion);
#[async_trait]
pub trait Tool: Send + Sync + DynClone {
async fn invoke(
&self,
agent_context: &dyn AgentContext,
tool_call: &ToolCall,
) -> Result<ToolOutput, ToolError>;
fn name(&self) -> Cow<'_, str>;
fn tool_spec(&self) -> ToolSpec;
fn boxed<'a>(self) -> Box<dyn Tool + 'a>
where
Self: Sized + 'a,
{
Box::new(self) as Box<dyn Tool>
}
}
#[async_trait]
pub trait ToolBox: Send + Sync + DynClone {
async fn available_tools(&self) -> Result<Vec<Box<dyn Tool>>>;
fn name(&self) -> Cow<'_, str> {
Cow::Borrowed("Unnamed ToolBox")
}
fn boxed<'a>(self) -> Box<dyn ToolBox + 'a>
where
Self: Sized + 'a,
{
Box::new(self) as Box<dyn ToolBox>
}
}
#[async_trait]
impl ToolBox for Vec<Box<dyn Tool>> {
async fn available_tools(&self) -> Result<Vec<Box<dyn Tool>>> {
Ok(self.clone())
}
}
#[async_trait]
impl ToolBox for Box<dyn ToolBox> {
async fn available_tools(&self) -> Result<Vec<Box<dyn Tool>>> {
(**self).available_tools().await
}
}
#[async_trait]
impl ToolBox for Arc<dyn ToolBox> {
async fn available_tools(&self) -> Result<Vec<Box<dyn Tool>>> {
(**self).available_tools().await
}
}
#[async_trait]
impl ToolBox for &dyn ToolBox {
async fn available_tools(&self) -> Result<Vec<Box<dyn Tool>>> {
(**self).available_tools().await
}
}
#[async_trait]
impl ToolBox for &[Box<dyn Tool>] {
async fn available_tools(&self) -> Result<Vec<Box<dyn Tool>>> {
Ok(self.to_vec())
}
}
#[async_trait]
impl ToolBox for [Box<dyn Tool>] {
async fn available_tools(&self) -> Result<Vec<Box<dyn Tool>>> {
Ok(self.to_vec())
}
}
dyn_clone::clone_trait_object!(ToolBox);
#[async_trait]
impl Tool for Box<dyn Tool> {
async fn invoke(
&self,
agent_context: &dyn AgentContext,
tool_call: &ToolCall,
) -> Result<ToolOutput, ToolError> {
(**self).invoke(agent_context, tool_call).await
}
fn name(&self) -> Cow<'_, str> {
(**self).name()
}
fn tool_spec(&self) -> ToolSpec {
(**self).tool_spec()
}
}
dyn_clone::clone_trait_object!(Tool);
impl PartialEq for Box<dyn Tool> {
fn eq(&self, other: &Self) -> bool {
self.name() == other.name()
}
}
impl Eq for Box<dyn Tool> {}
impl std::hash::Hash for Box<dyn Tool> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name().hash(state);
}
}