use crate::error::Result;
use crate::config::Config;
use crate::session::SessionManager;
use crate::tools::ToolRegistry;
use crate::agent::context::{AgentContext, Message, MessageRole, ContextMetadata};
use crate::llm::framework::LlmProvider;
use std::sync::Arc;
use std::path::Path;
pub struct AgentLoop {
config: Config,
session_manager: Arc<SessionManager>,
tool_registry: Arc<ToolRegistry>,
llm_provider: Arc<dyn LlmProvider>,
#[allow(dead_code)]
workspace: String,
}
impl AgentLoop {
pub async fn new(
config: Config,
workspace: impl AsRef<Path>,
llm_provider: Arc<dyn LlmProvider>,
) -> Result<Self> {
let workspace_str = workspace.as_ref().to_string_lossy().to_string();
let sessions_path = Path::new(&workspace_str).join("sessions");
let session_manager = Arc::new(
SessionManager::with_storage(&sessions_path)
.unwrap_or_else(|_| SessionManager::new()),
);
let tool_registry = Arc::new(ToolRegistry::new());
Ok(AgentLoop {
config,
session_manager,
tool_registry,
llm_provider,
workspace: workspace_str,
})
}
pub async fn process_message(
&self,
session_id: &str,
user_id: &str,
channel: &str,
user_message: &str,
) -> Result<String> {
let mut session = self
.session_manager
.get_or_create(session_id, user_id)
.await?;
session.metadata.channel = channel.to_string();
let user_msg = Message {
role: MessageRole::User,
content: user_message.to_string(),
timestamp: std::time::SystemTime::now(),
};
session.messages.push(user_msg.clone());
self.session_manager.save_session(&session).await?;
let context = AgentContext {
session_id: session_id.to_string(),
user_input: user_message.to_string(),
conversation_history: session.messages.clone(),
available_tools: self.tool_registry.list().await,
metadata: ContextMetadata {
channel: channel.to_string(),
user_id: user_id.to_string(),
tags: session.metadata.tags.clone(),
},
};
let response = self
.llm_provider
.chat(
&context.conversation_history,
&self.tool_registry.get_definitions().await,
&self.config.llm.default_provider,
)
.await?;
let assistant_msg = Message {
role: MessageRole::Assistant,
content: response.clone(),
timestamp: std::time::SystemTime::now(),
};
session.messages.push(assistant_msg);
self.session_manager.save_session(&session).await?;
Ok(response)
}
pub fn session_manager(&self) -> Arc<SessionManager> {
self.session_manager.clone()
}
pub fn tool_registry(&self) -> Arc<ToolRegistry> {
self.tool_registry.clone()
}
}
impl Default for AgentLoop {
fn default() -> Self {
panic!("AgentLoop requires configuration and LLM provider")
}
}