use crate::cook::execution::errors::{ErrorContext, MapReduceError, SpanInfo};
use crate::worktree::WorktreeSession;
use chrono::Utc;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
pub struct AgentResourceManager {
active_contexts: Arc<RwLock<HashMap<String, AgentContext>>>,
}
impl AgentResourceManager {
pub fn new() -> Self {
Self {
active_contexts: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn create_worktree_error(
&self,
agent_id: &str,
reason: String,
correlation_id: &str,
) -> MapReduceError {
let context = create_error_context("worktree_creation", correlation_id);
MapReduceError::WorktreeCreationFailed {
agent_id: agent_id.to_string(),
reason: reason.clone(),
source: std::io::Error::other(reason),
}
.with_context(context)
.error
}
pub fn initialize_agent_context(
&self,
agent_id: &str,
item: &Value,
item_index: usize,
worktree_session: &WorktreeSession,
correlation_id: &str,
) -> HashMap<String, Value> {
let mut context = HashMap::new();
context.insert("item".to_string(), item.clone());
context.insert("item_index".to_string(), Value::Number(item_index.into()));
context.insert("agent_id".to_string(), Value::String(agent_id.to_string()));
context.insert(
"worktree_name".to_string(),
Value::String(worktree_session.name.clone()),
);
context.insert(
"worktree_path".to_string(),
Value::String(worktree_session.path.display().to_string()),
);
let mapreduce_context = serde_json::json!({
"job_id": correlation_id,
"agent": {
"id": agent_id,
"index": item_index,
"worktree": &worktree_session.name,
},
"item": item,
});
context.insert("map".to_string(), mapreduce_context);
context
}
pub async fn register_context(&self, agent_id: String, context: AgentContext) {
let mut contexts = self.active_contexts.write().await;
contexts.insert(agent_id, context);
}
pub async fn unregister_context(&self, agent_id: &str) -> Option<AgentContext> {
let mut contexts = self.active_contexts.write().await;
contexts.remove(agent_id)
}
pub async fn get_active_contexts(&self) -> Vec<(String, AgentContext)> {
let contexts = self.active_contexts.read().await;
contexts
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect()
}
pub async fn get_context(&self, agent_id: &str) -> Option<AgentContext> {
let contexts = self.active_contexts.read().await;
contexts.get(agent_id).cloned()
}
}
#[derive(Debug, Clone)]
pub struct AgentContext {
pub agent_id: String,
pub item: Value,
pub item_index: usize,
pub worktree_session: WorktreeSession,
pub variables: HashMap<String, Value>,
}
impl AgentContext {
pub fn new(
agent_id: String,
item: Value,
item_index: usize,
worktree_session: WorktreeSession,
variables: HashMap<String, Value>,
) -> Self {
Self {
agent_id,
item,
item_index,
worktree_session,
variables,
}
}
pub fn working_directory(&self) -> std::path::PathBuf {
self.worktree_session.path.clone()
}
pub fn branch_name(&self) -> String {
self.worktree_session.branch.clone()
}
}
fn create_error_context(span_name: &str, correlation_id: &str) -> ErrorContext {
ErrorContext {
correlation_id: correlation_id.to_string(),
timestamp: Utc::now(),
hostname: std::env::var("HOSTNAME").unwrap_or_else(|_| "localhost".to_string()),
thread_id: format!("{:?}", std::thread::current().id()),
span_trace: vec![SpanInfo {
name: span_name.to_string(),
start: Utc::now(),
attributes: HashMap::new(),
}],
}
}
impl Default for AgentResourceManager {
fn default() -> Self {
Self::new()
}
}