use std::sync::{Arc, Mutex};
use crate::chat_completion::{ChatMessage, ToolCall};
use anyhow::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
pub use crate::command_output::{CommandOutput, CommandOutputChunk};
pub use crate::tool_executor::*;
#[derive(Debug, Clone, Serialize, Deserialize, strum_macros::EnumIs)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub enum ToolFeedback {
Approved { payload: Option<serde_json::Value> },
Refused { payload: Option<serde_json::Value> },
}
impl ToolFeedback {
pub fn approved() -> Self {
ToolFeedback::Approved { payload: None }
}
pub fn refused() -> Self {
ToolFeedback::Refused { payload: None }
}
pub fn payload(&self) -> Option<&serde_json::Value> {
match self {
ToolFeedback::Refused { payload } | ToolFeedback::Approved { payload } => {
payload.as_ref()
}
}
}
#[must_use]
pub fn with_payload(self, payload: serde_json::Value) -> Self {
match self {
ToolFeedback::Approved { .. } => ToolFeedback::Approved {
payload: Some(payload),
},
ToolFeedback::Refused { .. } => ToolFeedback::Refused {
payload: Some(payload),
},
}
}
}
#[async_trait]
pub trait AgentContext: Send + Sync {
async fn next_completion(&self) -> Result<Option<Vec<ChatMessage>>>;
async fn current_new_messages(&self) -> Result<Vec<ChatMessage>>;
async fn add_messages(&self, item: Vec<ChatMessage>) -> Result<()>;
async fn add_message(&self, item: ChatMessage) -> Result<()>;
#[deprecated(note = "use executor instead")]
async fn exec_cmd(&self, cmd: &Command) -> Result<CommandOutput, CommandError>;
fn executor(&self) -> &Arc<dyn ToolExecutor>;
async fn history(&self) -> Result<Vec<ChatMessage>>;
async fn replace_history(&self, items: Vec<ChatMessage>) -> Result<()>;
async fn redrive(&self) -> Result<()>;
async fn has_received_feedback(&self, tool_call: &ToolCall) -> Option<ToolFeedback>;
async fn feedback_received(&self, tool_call: &ToolCall, feedback: &ToolFeedback) -> Result<()>;
}
#[async_trait]
impl AgentContext for Box<dyn AgentContext> {
async fn next_completion(&self) -> Result<Option<Vec<ChatMessage>>> {
(**self).next_completion().await
}
async fn current_new_messages(&self) -> Result<Vec<ChatMessage>> {
(**self).current_new_messages().await
}
async fn add_messages(&self, item: Vec<ChatMessage>) -> Result<()> {
(**self).add_messages(item).await
}
async fn add_message(&self, item: ChatMessage) -> Result<()> {
(**self).add_message(item).await
}
#[allow(deprecated)]
async fn exec_cmd(&self, cmd: &Command) -> Result<CommandOutput, CommandError> {
(**self).exec_cmd(cmd).await
}
fn executor(&self) -> &Arc<dyn ToolExecutor> {
(**self).executor()
}
async fn history(&self) -> Result<Vec<ChatMessage>> {
(**self).history().await
}
async fn replace_history(&self, items: Vec<ChatMessage>) -> Result<()> {
(**self).replace_history(items).await
}
async fn redrive(&self) -> Result<()> {
(**self).redrive().await
}
async fn has_received_feedback(&self, tool_call: &ToolCall) -> Option<ToolFeedback> {
(**self).has_received_feedback(tool_call).await
}
async fn feedback_received(&self, tool_call: &ToolCall, feedback: &ToolFeedback) -> Result<()> {
(**self).feedback_received(tool_call, feedback).await
}
}
#[async_trait]
impl AgentContext for Arc<dyn AgentContext> {
async fn next_completion(&self) -> Result<Option<Vec<ChatMessage>>> {
(**self).next_completion().await
}
async fn current_new_messages(&self) -> Result<Vec<ChatMessage>> {
(**self).current_new_messages().await
}
async fn add_messages(&self, item: Vec<ChatMessage>) -> Result<()> {
(**self).add_messages(item).await
}
async fn add_message(&self, item: ChatMessage) -> Result<()> {
(**self).add_message(item).await
}
#[allow(deprecated)]
async fn exec_cmd(&self, cmd: &Command) -> Result<CommandOutput, CommandError> {
(**self).exec_cmd(cmd).await
}
fn executor(&self) -> &Arc<dyn ToolExecutor> {
(**self).executor()
}
async fn history(&self) -> Result<Vec<ChatMessage>> {
(**self).history().await
}
async fn replace_history(&self, items: Vec<ChatMessage>) -> Result<()> {
(**self).replace_history(items).await
}
async fn redrive(&self) -> Result<()> {
(**self).redrive().await
}
async fn has_received_feedback(&self, tool_call: &ToolCall) -> Option<ToolFeedback> {
(**self).has_received_feedback(tool_call).await
}
async fn feedback_received(&self, tool_call: &ToolCall, feedback: &ToolFeedback) -> Result<()> {
(**self).feedback_received(tool_call, feedback).await
}
}
#[async_trait]
impl AgentContext for &dyn AgentContext {
async fn next_completion(&self) -> Result<Option<Vec<ChatMessage>>> {
(**self).next_completion().await
}
async fn current_new_messages(&self) -> Result<Vec<ChatMessage>> {
(**self).current_new_messages().await
}
async fn add_messages(&self, item: Vec<ChatMessage>) -> Result<()> {
(**self).add_messages(item).await
}
async fn add_message(&self, item: ChatMessage) -> Result<()> {
(**self).add_message(item).await
}
#[allow(deprecated)]
async fn exec_cmd(&self, cmd: &Command) -> Result<CommandOutput, CommandError> {
(**self).exec_cmd(cmd).await
}
fn executor(&self) -> &Arc<dyn ToolExecutor> {
(**self).executor()
}
async fn history(&self) -> Result<Vec<ChatMessage>> {
(**self).history().await
}
async fn replace_history(&self, items: Vec<ChatMessage>) -> Result<()> {
(**self).replace_history(items).await
}
async fn redrive(&self) -> Result<()> {
(**self).redrive().await
}
async fn has_received_feedback(&self, tool_call: &ToolCall) -> Option<ToolFeedback> {
(**self).has_received_feedback(tool_call).await
}
async fn feedback_received(&self, tool_call: &ToolCall, feedback: &ToolFeedback) -> Result<()> {
(**self).feedback_received(tool_call, feedback).await
}
}
#[async_trait]
impl AgentContext for () {
async fn next_completion(&self) -> Result<Option<Vec<ChatMessage>>> {
Ok(None)
}
async fn current_new_messages(&self) -> Result<Vec<ChatMessage>> {
Ok(Vec::new())
}
async fn add_messages(&self, _item: Vec<ChatMessage>) -> Result<()> {
Ok(())
}
async fn add_message(&self, _item: ChatMessage) -> Result<()> {
Ok(())
}
async fn exec_cmd(&self, _cmd: &Command) -> Result<CommandOutput, CommandError> {
Err(CommandError::ExecutorError(anyhow::anyhow!(
"Empty agent context does not have a tool executor"
)))
}
fn executor(&self) -> &Arc<dyn ToolExecutor> {
unimplemented!("Empty agent context does not have a tool executor")
}
async fn history(&self) -> Result<Vec<ChatMessage>> {
Ok(Vec::new())
}
async fn replace_history(&self, _items: Vec<ChatMessage>) -> Result<()> {
Ok(())
}
async fn redrive(&self) -> Result<()> {
Ok(())
}
async fn has_received_feedback(&self, _tool_call: &ToolCall) -> Option<ToolFeedback> {
Some(ToolFeedback::Approved { payload: None })
}
async fn feedback_received(
&self,
_tool_call: &ToolCall,
_feedback: &ToolFeedback,
) -> Result<()> {
Ok(())
}
}
#[async_trait]
pub trait MessageHistory: Send + Sync + std::fmt::Debug {
async fn history(&self) -> Result<Vec<ChatMessage>>;
async fn push_owned(&self, item: ChatMessage) -> Result<()>;
async fn overwrite(&self, items: Vec<ChatMessage>) -> Result<()>;
async fn push(&self, item: &ChatMessage) -> Result<()> {
self.push_owned(item.to_owned()).await
}
async fn extend(&self, items: &[ChatMessage]) -> Result<()> {
self.extend_owned(items.iter().map(ChatMessage::to_owned).collect())
.await
}
async fn extend_owned(&self, items: Vec<ChatMessage>) -> Result<()> {
for item in items {
self.push_owned(item).await?;
}
Ok(())
}
}
#[async_trait]
impl MessageHistory for Mutex<Vec<ChatMessage>> {
async fn history(&self) -> Result<Vec<ChatMessage>> {
Ok(self.lock().unwrap().clone())
}
async fn push_owned(&self, item: ChatMessage) -> Result<()> {
self.lock().unwrap().push(item);
Ok(())
}
async fn overwrite(&self, items: Vec<ChatMessage>) -> Result<()> {
let mut lock = self.lock().unwrap();
*lock = items;
Ok(())
}
}