use crate::agents::agent::AgentGPT;
#[cfg(feature = "net")]
use crate::collaboration::Collaborator;
use crate::common::utils::{
Capability, ClientType, ContextManager, Knowledge, Message, Persona, Planner, Reflection,
Status, Task, TaskScheduler, Tool,
};
use crate::traits::agent::Agent;
use crate::traits::functions::{AsyncFunctions, Executor, Functions, ReqResponse};
use anyhow::{Result, anyhow};
use async_trait::async_trait;
use auto_derive::Auto;
use colored::*;
use nylas::client::Nylas;
use nylas::messages::Message as NylasMessage;
use std::borrow::Cow;
use std::env::var;
use tracing::{debug, info};
#[cfg(feature = "mem")]
use {
crate::common::memory::load_long_term_memory, crate::common::memory::long_term_memory_context,
crate::common::memory::save_long_term_memory,
};
#[cfg(feature = "hf")]
use crate::prelude::hf_model_from_str;
#[derive(Auto, Default)]
#[allow(unused)]
pub struct MailerGPT {
agent: AgentGPT,
task: Task,
nylas_client: Option<Nylas>,
client: ClientType,
}
impl std::fmt::Debug for MailerGPT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MailerGPT")
.field("agent", &self.agent)
.field("task", &self.task)
.field("client", &self.client)
.finish()
}
}
impl Clone for MailerGPT {
fn clone(&self) -> Self {
Self {
agent: self.agent.clone(),
task: self.task.clone(),
nylas_client: None,
client: self.client.clone(),
}
}
}
impl MailerGPT {
pub async fn new(persona: &'static str, behavior: &'static str) -> Self {
let mut agent: AgentGPT = AgentGPT::new_borrowed(persona, behavior);
agent.id = agent.persona().to_string().into();
let client_id = var("NYLAS_CLIENT_ID").unwrap_or_default().to_owned();
let client_secret = var("NYLAS_CLIENT_SECRET").unwrap_or_default().to_owned();
let access_token = var("NYLAS_ACCESS_TOKEN").unwrap_or_default().to_owned();
let nylas_client = Nylas::new(&client_id, &client_secret, Some(&access_token))
.await
.unwrap();
let client = ClientType::from_env();
info!(
"{}",
format!("[*] {:?}: 🛠️ Getting ready!", agent.persona(),)
.bright_white()
.bold()
);
Self {
agent,
task: Task::default(),
nylas_client: Some(nylas_client),
client,
}
}
pub async fn get_latest_emails(&mut self) -> Result<Vec<NylasMessage>> {
let nylas = self
.nylas_client
.as_mut()
.ok_or_else(|| anyhow!("Nylas client not initialized"))?;
let messages = nylas.messages().all().await.unwrap();
info!(
"[*] {:?}: Read {:?} Messages",
self.agent.persona(),
messages.len()
);
Ok(messages[95..].to_vec())
}
pub async fn generate_text_from_emails(&mut self, prompt: &str) -> Result<String> {
self.agent.add_message(Message {
role: Cow::Borrowed("user"),
content: Cow::Owned(format!(
"Requested to generate text based on emails with prompt: '{prompt}'"
)),
});
#[cfg(feature = "mem")]
{
let _ = self
.save_ltm(Message {
role: Cow::Borrowed("user"),
content: Cow::Owned(format!(
"Requested to generate text based on emails with prompt: '{prompt}'"
)),
})
.await;
}
let emails = match self.get_latest_emails().await {
Ok(e) => e,
Err(err) => {
let error_msg = format!("Failed to fetch latest emails: {err}");
self.agent.add_message(Message {
role: Cow::Borrowed("system"),
content: Cow::Owned(error_msg.clone()),
});
#[cfg(feature = "mem")]
{
let _ = self
.save_ltm(Message {
role: Cow::Borrowed("system"),
content: Cow::Owned(error_msg.clone()),
})
.await;
}
return Err(anyhow!(error_msg));
}
};
self.agent.add_message(Message {
role: Cow::Borrowed("assistant"),
content: Cow::Owned(
"Analyzing latest emails and generating text based on provided prompt..."
.to_string(),
),
});
#[cfg(feature = "mem")]
{
let _ = self
.save_ltm(Message {
role: Cow::Borrowed("assistant"),
content: Cow::Owned(
"Analyzing latest emails and generating text based on provided prompt..."
.to_string(),
),
})
.await;
}
let full_prompt = format!("User Request:{prompt}\n\nEmails:{emails:?}");
let gemini_response = self.generate(&full_prompt).await?;
self.agent.add_message(Message {
role: Cow::Borrowed("assistant"),
content: Cow::Owned(
"Generated text from emails based on the given prompt.".to_string(),
),
});
#[cfg(feature = "mem")]
{
let _ = self
.save_ltm(Message {
role: Cow::Borrowed("assistant"),
content: Cow::Owned(
"Generated text from emails based on the given prompt.".to_string(),
),
})
.await;
}
info!(
"[*] {:?}: Got Response: {:?}",
self.agent.persona(),
gemini_response
);
Ok(gemini_response)
}
}
#[async_trait]
impl Executor for MailerGPT {
async fn execute<'a>(
&'a mut self,
task: &'a mut Task,
_execute: bool,
_browse: bool,
_max_tries: u64,
) -> Result<()> {
info!(
"{}",
format!("[*] {:?}: Executing task:", self.agent.persona(),)
.bright_white()
.bold()
);
for task in task.clone().description.clone().split("- ") {
if !task.trim().is_empty() {
info!("{} {}", "•".bright_white().bold(), task.trim().cyan());
}
}
let mut _count = 0;
while self.agent.status() != &Status::Completed {
match self.agent.status() {
Status::Idle => {
debug!("[*] {:?}: Idle", self.agent.persona());
let _generated_text = self.generate_text_from_emails(&task.description).await?;
_count += 1;
self.agent.update(Status::Completed);
}
_ => {
self.agent.update(Status::Completed);
}
}
}
Ok(())
}
}