use crate::basic::keywords::auto_task::{ AutoTask, AutoTaskStatus, ExecutionMode, PendingApproval, PendingDecision, TaskPriority, }; use crate::basic::keywords::intent_compiler::IntentCompiler; use crate::basic::keywords::safety_layer::{SafetyLayer, SimulationResult}; use crate::shared::state::AppState; use axum::{ extract::{Path, Query, State}, http::StatusCode, response::IntoResponse, Json, }; use chrono::Utc; use log::{error, info, trace}; use serde::{Deserialize, Serialize}; use std::sync::Arc; use uuid::Uuid; #[derive(Debug, Deserialize)] pub struct CompileIntentRequest { pub intent: String, pub execution_mode: Option, pub priority: Option, } #[derive(Debug, Serialize)] pub struct CompileIntentResponse { pub success: bool, pub plan_id: Option, pub plan_name: Option, pub plan_description: Option, pub steps: Vec, pub alternatives: Vec, pub confidence: f64, pub risk_level: String, pub estimated_duration_minutes: i32, pub estimated_cost: f64, pub resource_estimate: ResourceEstimateResponse, pub basic_program: Option, pub requires_approval: bool, pub mcp_servers: Vec, pub external_apis: Vec, pub risks: Vec, pub error: Option, } #[derive(Debug, Serialize)] pub struct PlanStepResponse { pub id: String, pub order: i32, pub name: String, pub description: String, pub keywords: Vec, pub priority: String, pub risk_level: String, pub estimated_minutes: i32, pub requires_approval: bool, } #[derive(Debug, Serialize)] pub struct AlternativeResponse { pub id: String, pub description: String, pub confidence: f64, pub pros: Vec, pub cons: Vec, pub estimated_cost: Option, pub estimated_time_hours: Option, } #[derive(Debug, Serialize)] pub struct ResourceEstimateResponse { pub compute_hours: f64, pub storage_gb: f64, pub api_calls: i32, pub llm_tokens: i32, pub estimated_cost_usd: f64, } #[derive(Debug, Serialize)] pub struct RiskResponse { pub id: String, pub category: String, pub description: String, pub probability: f64, pub impact: String, } #[derive(Debug, Deserialize)] pub struct ExecutePlanRequest { pub plan_id: String, pub execution_mode: Option, pub priority: Option, } #[derive(Debug, Serialize)] pub struct ExecutePlanResponse { pub success: bool, pub task_id: Option, pub status: Option, pub error: Option, } #[derive(Debug, Deserialize)] pub struct ListTasksQuery { pub filter: Option, pub status: Option, pub priority: Option, pub limit: Option, pub offset: Option, } #[derive(Debug, Serialize)] pub struct AutoTaskStatsResponse { pub total: i32, pub running: i32, pub pending: i32, pub completed: i32, pub failed: i32, pub pending_approval: i32, pub pending_decision: i32, } #[derive(Debug, Serialize)] pub struct TaskActionResponse { pub success: bool, pub message: Option, pub error: Option, } #[derive(Debug, Deserialize)] pub struct DecisionRequest { pub decision_id: String, pub option_id: Option, pub skip: Option, } #[derive(Debug, Deserialize)] pub struct ApprovalRequest { pub approval_id: String, pub action: String, pub comment: Option, } #[derive(Debug, Serialize)] pub struct SimulationResponse { pub success: bool, pub confidence: f64, pub risk_score: f64, pub risk_level: String, pub step_outcomes: Vec, pub impact: ImpactResponse, pub side_effects: Vec, pub recommendations: Vec, pub error: Option, } #[derive(Debug, Serialize)] pub struct StepOutcomeResponse { pub step_id: String, pub step_name: String, pub would_succeed: bool, pub success_probability: f64, pub failure_modes: Vec, } #[derive(Debug, Serialize)] pub struct ImpactResponse { pub risk_score: f64, pub risk_level: String, pub data_impact: DataImpactResponse, pub cost_impact: CostImpactResponse, pub time_impact: TimeImpactResponse, pub security_impact: SecurityImpactResponse, } #[derive(Debug, Serialize)] pub struct DataImpactResponse { pub records_created: i32, pub records_modified: i32, pub records_deleted: i32, pub tables_affected: Vec, pub reversible: bool, } #[derive(Debug, Serialize)] pub struct CostImpactResponse { pub api_costs: f64, pub compute_costs: f64, pub storage_costs: f64, pub total_estimated_cost: f64, } #[derive(Debug, Serialize)] pub struct TimeImpactResponse { pub estimated_duration_seconds: i32, pub blocking: bool, } #[derive(Debug, Serialize)] pub struct SecurityImpactResponse { pub risk_level: String, pub credentials_accessed: Vec, pub external_systems: Vec, pub concerns: Vec, } #[derive(Debug, Serialize)] pub struct SideEffectResponse { pub effect_type: String, pub description: String, pub severity: String, pub mitigation: Option, } #[derive(Debug, Serialize)] pub struct RecommendationResponse { pub id: String, pub recommendation_type: String, pub description: String, pub action: Option, } pub async fn compile_intent_handler( State(state): State>, Json(request): Json, ) -> impl IntoResponse { info!( "Compiling intent: {}", &request.intent[..request.intent.len().min(100)] ); let session = match get_current_session(&state).await { Ok(s) => s, Err(e) => { return ( StatusCode::UNAUTHORIZED, Json(CompileIntentResponse { success: false, plan_id: None, plan_name: None, plan_description: None, steps: Vec::new(), alternatives: Vec::new(), confidence: 0.0, risk_level: "unknown".to_string(), estimated_duration_minutes: 0, estimated_cost: 0.0, resource_estimate: ResourceEstimateResponse { compute_hours: 0.0, storage_gb: 0.0, api_calls: 0, llm_tokens: 0, estimated_cost_usd: 0.0, }, basic_program: None, requires_approval: false, mcp_servers: Vec::new(), external_apis: Vec::new(), risks: Vec::new(), error: Some(format!("Authentication error: {}", e)), }), ); } }; let compiler = IntentCompiler::new(Arc::clone(&state)); match compiler.compile(&request.intent, &session).await { Ok(compiled) => { let response = CompileIntentResponse { success: true, plan_id: Some(compiled.plan.id.clone()), plan_name: Some(compiled.plan.name.clone()), plan_description: Some(compiled.plan.description.clone()), steps: compiled .plan .steps .iter() .map(|s| PlanStepResponse { id: s.id.clone(), order: s.order, name: s.name.clone(), description: s.description.clone(), keywords: s.keywords.clone(), priority: format!("{:?}", s.priority), risk_level: format!("{:?}", s.risk_level), estimated_minutes: s.estimated_minutes, requires_approval: s.requires_approval, }) .collect(), alternatives: compiled .alternatives .iter() .map(|a| AlternativeResponse { id: a.id.clone(), description: a.description.clone(), confidence: a.confidence, pros: a.pros.clone(), cons: a.cons.clone(), estimated_cost: a.estimated_cost, estimated_time_hours: a.estimated_time_hours, }) .collect(), confidence: compiled.confidence, risk_level: format!("{:?}", compiled.risk_assessment.overall_risk), estimated_duration_minutes: compiled.plan.estimated_duration_minutes, estimated_cost: compiled.resource_estimate.estimated_cost_usd, resource_estimate: ResourceEstimateResponse { compute_hours: compiled.resource_estimate.compute_hours, storage_gb: compiled.resource_estimate.storage_gb, api_calls: compiled.resource_estimate.api_calls, llm_tokens: compiled.resource_estimate.llm_tokens, estimated_cost_usd: compiled.resource_estimate.estimated_cost_usd, }, basic_program: Some(compiled.basic_program.clone()), requires_approval: compiled.plan.requires_approval, mcp_servers: compiled.resource_estimate.mcp_servers_needed.clone(), external_apis: compiled.resource_estimate.external_services.clone(), risks: compiled .risk_assessment .risks .iter() .map(|r| RiskResponse { id: r.id.clone(), category: format!("{:?}", r.category), description: r.description.clone(), probability: r.probability, impact: format!("{:?}", r.impact), }) .collect(), error: None, }; (StatusCode::OK, Json(response)) } Err(e) => { error!("Failed to compile intent: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(CompileIntentResponse { success: false, plan_id: None, plan_name: None, plan_description: None, steps: Vec::new(), alternatives: Vec::new(), confidence: 0.0, risk_level: "unknown".to_string(), estimated_duration_minutes: 0, estimated_cost: 0.0, resource_estimate: ResourceEstimateResponse { compute_hours: 0.0, storage_gb: 0.0, api_calls: 0, llm_tokens: 0, estimated_cost_usd: 0.0, }, basic_program: None, requires_approval: false, mcp_servers: Vec::new(), external_apis: Vec::new(), risks: Vec::new(), error: Some(e.to_string()), }), ) } } } pub async fn execute_plan_handler( State(state): State>, Json(request): Json, ) -> impl IntoResponse { info!("Executing plan: {}", request.plan_id); let session = match get_current_session(&state).await { Ok(s) => s, Err(e) => { return ( StatusCode::UNAUTHORIZED, Json(ExecutePlanResponse { success: false, task_id: None, status: None, error: Some(format!("Authentication error: {}", e)), }), ); } }; let execution_mode = match request.execution_mode.as_deref() { Some("fully-automatic") => ExecutionMode::FullyAutomatic, Some("supervised") => ExecutionMode::Supervised, Some("manual") => ExecutionMode::Manual, Some("dry-run") => ExecutionMode::DryRun, _ => ExecutionMode::SemiAutomatic, }; let priority = match request.priority.as_deref() { Some("critical") => TaskPriority::Critical, Some("high") => TaskPriority::High, Some("low") => TaskPriority::Low, Some("background") => TaskPriority::Background, _ => TaskPriority::Medium, }; match create_auto_task_from_plan(&state, &session, &request.plan_id, execution_mode, priority) .await { Ok(task) => { match start_task_execution(&state, &task.id).await { Ok(_) => ( StatusCode::OK, Json(ExecutePlanResponse { success: true, task_id: Some(task.id), status: Some(task.status.to_string()), error: None, }), ), Err(e) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(ExecutePlanResponse { success: false, task_id: Some(task.id), status: Some("failed".to_string()), error: Some(e.to_string()), }), ), } } Err(e) => { error!("Failed to create task: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(ExecutePlanResponse { success: false, task_id: None, status: None, error: Some(e.to_string()), }), ) } } } pub async fn list_tasks_handler( State(state): State>, Query(query): Query, ) -> impl IntoResponse { let filter = query.filter.as_deref().unwrap_or("all"); let limit = query.limit.unwrap_or(50); let offset = query.offset.unwrap_or(0); match list_auto_tasks(&state, filter, limit, offset).await { Ok(tasks) => { let html = render_task_list_html(&tasks); (StatusCode::OK, axum::response::Html(html)) } Err(e) => { error!("Failed to list tasks: {}", e); let html = format!( r#"

Failed to load tasks: {}

"#, html_escape(&e.to_string()) ); ( StatusCode::INTERNAL_SERVER_ERROR, axum::response::Html(html), ) } } } pub async fn get_stats_handler(State(state): State>) -> impl IntoResponse { match get_auto_task_stats(&state).await { Ok(stats) => (StatusCode::OK, Json(stats)), Err(e) => { error!("Failed to get stats: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(AutoTaskStatsResponse { total: 0, running: 0, pending: 0, completed: 0, failed: 0, pending_approval: 0, pending_decision: 0, }), ) } } } pub async fn pause_task_handler( State(state): State>, Path(task_id): Path, ) -> impl IntoResponse { match update_task_status(&state, &task_id, AutoTaskStatus::Paused).await { Ok(_) => ( StatusCode::OK, Json(TaskActionResponse { success: true, message: Some("Task paused".to_string()), error: None, }), ), Err(e) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(TaskActionResponse { success: false, message: None, error: Some(e.to_string()), }), ), } } pub async fn resume_task_handler( State(state): State>, Path(task_id): Path, ) -> impl IntoResponse { match update_task_status(&state, &task_id, AutoTaskStatus::Running).await { Ok(_) => { let _ = start_task_execution(&state, &task_id).await; ( StatusCode::OK, Json(TaskActionResponse { success: true, message: Some("Task resumed".to_string()), error: None, }), ) } Err(e) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(TaskActionResponse { success: false, message: None, error: Some(e.to_string()), }), ), } } pub async fn cancel_task_handler( State(state): State>, Path(task_id): Path, ) -> impl IntoResponse { match update_task_status(&state, &task_id, AutoTaskStatus::Cancelled).await { Ok(_) => ( StatusCode::OK, Json(TaskActionResponse { success: true, message: Some("Task cancelled".to_string()), error: None, }), ), Err(e) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(TaskActionResponse { success: false, message: None, error: Some(e.to_string()), }), ), } } pub async fn simulate_task_handler( State(state): State>, Path(task_id): Path, ) -> impl IntoResponse { let session = match get_current_session(&state).await { Ok(s) => s, Err(e) => { return ( StatusCode::UNAUTHORIZED, Json(SimulationResponse { success: false, confidence: 0.0, risk_score: 0.0, risk_level: "unknown".to_string(), step_outcomes: Vec::new(), impact: ImpactResponse { risk_score: 0.0, risk_level: "unknown".to_string(), data_impact: DataImpactResponse { records_created: 0, records_modified: 0, records_deleted: 0, tables_affected: Vec::new(), reversible: true, }, cost_impact: CostImpactResponse { api_costs: 0.0, compute_costs: 0.0, storage_costs: 0.0, total_estimated_cost: 0.0, }, time_impact: TimeImpactResponse { estimated_duration_seconds: 0, blocking: false, }, security_impact: SecurityImpactResponse { risk_level: "unknown".to_string(), credentials_accessed: Vec::new(), external_systems: Vec::new(), concerns: Vec::new(), }, }, side_effects: Vec::new(), recommendations: Vec::new(), error: Some(format!("Authentication error: {}", e)), }), ); } }; let safety_layer = SafetyLayer::new(Arc::clone(&state)); match simulate_task_execution(&state, &safety_layer, &task_id, &session).await { Ok(result) => { let response = SimulationResponse { success: result.success, confidence: result.confidence, risk_score: result.impact.risk_score, risk_level: format!("{}", result.impact.risk_level), step_outcomes: result .step_outcomes .iter() .map(|s| StepOutcomeResponse { step_id: s.step_id.clone(), step_name: s.step_name.clone(), would_succeed: s.would_succeed, success_probability: s.success_probability, failure_modes: s .failure_modes .iter() .map(|f| f.failure_type.clone()) .collect(), }) .collect(), impact: ImpactResponse { risk_score: result.impact.risk_score, risk_level: format!("{}", result.impact.risk_level), data_impact: DataImpactResponse { records_created: result.impact.data_impact.records_created, records_modified: result.impact.data_impact.records_modified, records_deleted: result.impact.data_impact.records_deleted, tables_affected: result.impact.data_impact.tables_affected.clone(), reversible: result.impact.data_impact.reversible, }, cost_impact: CostImpactResponse { api_costs: result.impact.cost_impact.api_costs, compute_costs: result.impact.cost_impact.compute_costs, storage_costs: result.impact.cost_impact.storage_costs, total_estimated_cost: result.impact.cost_impact.total_estimated_cost, }, time_impact: TimeImpactResponse { estimated_duration_seconds: result .impact .time_impact .estimated_duration_seconds, blocking: result.impact.time_impact.blocking, }, security_impact: SecurityImpactResponse { risk_level: format!("{}", result.impact.security_impact.risk_level), credentials_accessed: result .impact .security_impact .credentials_accessed .clone(), external_systems: result.impact.security_impact.external_systems.clone(), concerns: result.impact.security_impact.concerns.clone(), }, }, side_effects: result .side_effects .iter() .map(|s| SideEffectResponse { effect_type: s.effect_type.clone(), description: s.description.clone(), severity: format!("{:?}", s.severity), mitigation: s.mitigation.clone(), }) .collect(), recommendations: result .recommendations .iter() .enumerate() .map(|(i, r)| RecommendationResponse { id: format!("rec-{}", i), recommendation_type: format!("{:?}", r.recommendation_type), description: r.description.clone(), action: r.action.clone(), }) .collect(), error: None, }; (StatusCode::OK, Json(response)) } Err(e) => { error!("Simulation failed: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(SimulationResponse { success: false, confidence: 0.0, risk_score: 1.0, risk_level: "unknown".to_string(), step_outcomes: Vec::new(), impact: ImpactResponse { risk_score: 1.0, risk_level: "unknown".to_string(), data_impact: DataImpactResponse { records_created: 0, records_modified: 0, records_deleted: 0, tables_affected: Vec::new(), reversible: true, }, cost_impact: CostImpactResponse { api_costs: 0.0, compute_costs: 0.0, storage_costs: 0.0, total_estimated_cost: 0.0, }, time_impact: TimeImpactResponse { estimated_duration_seconds: 0, blocking: false, }, security_impact: SecurityImpactResponse { risk_level: "unknown".to_string(), credentials_accessed: Vec::new(), external_systems: Vec::new(), concerns: Vec::new(), }, }, side_effects: Vec::new(), recommendations: Vec::new(), error: Some(e.to_string()), }), ) } } } pub async fn get_decisions_handler( State(state): State>, Path(task_id): Path, ) -> impl IntoResponse { match get_pending_decisions(&state, &task_id).await { Ok(decisions) => (StatusCode::OK, Json(decisions)), Err(e) => { error!("Failed to get decisions: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(Vec::::new()), ) } } } pub async fn submit_decision_handler( State(state): State>, Path(task_id): Path, Json(request): Json, ) -> impl IntoResponse { match submit_decision(&state, &task_id, &request).await { Ok(_) => ( StatusCode::OK, Json(TaskActionResponse { success: true, message: Some("Decision submitted".to_string()), error: None, }), ), Err(e) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(TaskActionResponse { success: false, message: None, error: Some(e.to_string()), }), ), } } pub async fn get_approvals_handler( State(state): State>, Path(task_id): Path, ) -> impl IntoResponse { match get_pending_approvals(&state, &task_id).await { Ok(approvals) => (StatusCode::OK, Json(approvals)), Err(e) => { error!("Failed to get approvals: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(Vec::::new()), ) } } } pub async fn submit_approval_handler( State(state): State>, Path(task_id): Path, Json(request): Json, ) -> impl IntoResponse { match submit_approval(&state, &task_id, &request).await { Ok(_) => ( StatusCode::OK, Json(TaskActionResponse { success: true, message: Some(format!("Approval {}", request.action)), error: None, }), ), Err(e) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(TaskActionResponse { success: false, message: None, error: Some(e.to_string()), }), ), } } pub async fn simulate_plan_handler( State(state): State>, Path(plan_id): Path, ) -> impl IntoResponse { let session = match get_current_session(&state).await { Ok(s) => s, Err(e) => { return ( StatusCode::UNAUTHORIZED, Json(SimulationResponse { success: false, confidence: 0.0, risk_score: 0.0, risk_level: "unknown".to_string(), step_outcomes: Vec::new(), impact: ImpactResponse { risk_score: 0.0, risk_level: "unknown".to_string(), data_impact: DataImpactResponse { records_created: 0, records_modified: 0, records_deleted: 0, tables_affected: Vec::new(), reversible: true, }, cost_impact: CostImpactResponse { api_costs: 0.0, compute_costs: 0.0, storage_costs: 0.0, total_estimated_cost: 0.0, }, time_impact: TimeImpactResponse { estimated_duration_seconds: 0, blocking: false, }, security_impact: SecurityImpactResponse { risk_level: "unknown".to_string(), credentials_accessed: Vec::new(), external_systems: Vec::new(), concerns: Vec::new(), }, }, side_effects: Vec::new(), recommendations: Vec::new(), error: Some(format!("Authentication error: {}", e)), }), ); } }; let safety_layer = SafetyLayer::new(Arc::clone(&state)); match simulate_plan_execution(&state, &safety_layer, &plan_id, &session).await { Ok(result) => { let response = SimulationResponse { success: result.success, confidence: result.confidence, risk_score: result.impact.risk_score, risk_level: format!("{}", result.impact.risk_level), step_outcomes: result .step_outcomes .iter() .map(|s| StepOutcomeResponse { step_id: s.step_id.clone(), step_name: s.step_name.clone(), would_succeed: s.would_succeed, success_probability: s.success_probability, failure_modes: s .failure_modes .iter() .map(|f| f.failure_type.clone()) .collect(), }) .collect(), impact: ImpactResponse { risk_score: result.impact.risk_score, risk_level: format!("{}", result.impact.risk_level), data_impact: DataImpactResponse { records_created: result.impact.data_impact.records_created, records_modified: result.impact.data_impact.records_modified, records_deleted: result.impact.data_impact.records_deleted, tables_affected: result.impact.data_impact.tables_affected.clone(), reversible: result.impact.data_impact.reversible, }, cost_impact: CostImpactResponse { api_costs: result.impact.cost_impact.api_costs, compute_costs: result.impact.cost_impact.compute_costs, storage_costs: result.impact.cost_impact.storage_costs, total_estimated_cost: result.impact.cost_impact.total_estimated_cost, }, time_impact: TimeImpactResponse { estimated_duration_seconds: result .impact .time_impact .estimated_duration_seconds, blocking: result.impact.time_impact.blocking, }, security_impact: SecurityImpactResponse { risk_level: format!("{}", result.impact.security_impact.risk_level), credentials_accessed: result .impact .security_impact .credentials_accessed .clone(), external_systems: result.impact.security_impact.external_systems.clone(), concerns: result.impact.security_impact.concerns.clone(), }, }, side_effects: result .side_effects .iter() .map(|s| SideEffectResponse { effect_type: s.effect_type.clone(), description: s.description.clone(), severity: format!("{:?}", s.severity), mitigation: s.mitigation.clone(), }) .collect(), recommendations: result .recommendations .iter() .enumerate() .map(|(i, r)| RecommendationResponse { id: format!("rec-{}", i), recommendation_type: format!("{:?}", r.recommendation_type), description: r.description.clone(), action: r.action.clone(), }) .collect(), error: None, }; (StatusCode::OK, Json(response)) } Err(e) => { error!("Plan simulation failed: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(SimulationResponse { success: false, confidence: 0.0, risk_score: 1.0, risk_level: "unknown".to_string(), step_outcomes: Vec::new(), impact: ImpactResponse { risk_score: 1.0, risk_level: "unknown".to_string(), data_impact: DataImpactResponse { records_created: 0, records_modified: 0, records_deleted: 0, tables_affected: Vec::new(), reversible: true, }, cost_impact: CostImpactResponse { api_costs: 0.0, compute_costs: 0.0, storage_costs: 0.0, total_estimated_cost: 0.0, }, time_impact: TimeImpactResponse { estimated_duration_seconds: 0, blocking: false, }, security_impact: SecurityImpactResponse { risk_level: "unknown".to_string(), credentials_accessed: Vec::new(), external_systems: Vec::new(), concerns: Vec::new(), }, }, side_effects: Vec::new(), recommendations: Vec::new(), error: Some(e.to_string()), }), ) } } } async fn get_current_session( state: &Arc, ) -> Result> { use crate::shared::models::user_sessions::dsl::*; use diesel::prelude::*; let mut conn = state .conn .get() .map_err(|e| format!("DB connection error: {}", e))?; let session = user_sessions .order(created_at.desc()) .first::(&mut conn) .optional() .map_err(|e| format!("DB query error: {}", e))? .ok_or_else(|| "No active session found")?; Ok(session) } async fn create_auto_task_from_plan( _state: &Arc, session: &crate::shared::models::UserSession, plan_id: &str, execution_mode: ExecutionMode, priority: TaskPriority, ) -> Result> { let task = AutoTask { id: Uuid::new_v4().to_string(), title: format!("Task from plan {}", plan_id), intent: String::new(), status: AutoTaskStatus::Ready, mode: execution_mode, priority, plan_id: Some(plan_id.to_string()), basic_program: None, current_step: 0, total_steps: 0, progress: 0.0, step_results: Vec::new(), pending_decisions: Vec::new(), pending_approvals: Vec::new(), risk_summary: None, resource_usage: crate::basic::keywords::auto_task::ResourceUsage::default(), error: None, rollback_state: None, session_id: session.id.to_string(), bot_id: session.bot_id.to_string(), created_by: session.user_id.to_string(), assigned_to: "auto".to_string(), schedule: None, tags: Vec::new(), parent_task_id: None, subtask_ids: Vec::new(), depends_on: Vec::new(), dependents: Vec::new(), mcp_servers: Vec::new(), external_apis: Vec::new(), created_at: Utc::now(), updated_at: Utc::now(), started_at: None, completed_at: None, estimated_completion: None, }; Ok(task) } async fn start_task_execution( _state: &Arc, task_id: &str, ) -> Result<(), Box> { info!("Starting task execution task_id={}", task_id); Ok(()) } async fn list_auto_tasks( _state: &Arc, _filter: &str, _limit: i32, _offset: i32, ) -> Result, Box> { Ok(Vec::new()) } async fn get_auto_task_stats( _state: &Arc, ) -> Result> { Ok(AutoTaskStatsResponse { total: 0, running: 0, pending: 0, completed: 0, failed: 0, pending_approval: 0, pending_decision: 0, }) } async fn update_task_status( _state: &Arc, task_id: &str, status: AutoTaskStatus, ) -> Result<(), Box> { info!( "Updating task status task_id={} status={:?}", task_id, status ); Ok(()) } async fn simulate_task_execution( _state: &Arc, safety_layer: &SafetyLayer, task_id: &str, session: &crate::shared::models::UserSession, ) -> Result> { info!("Simulating task execution task_id={}", task_id); safety_layer.simulate_execution(task_id, session).await } async fn simulate_plan_execution( _state: &Arc, safety_layer: &SafetyLayer, plan_id: &str, session: &crate::shared::models::UserSession, ) -> Result> { info!("Simulating plan execution plan_id={}", plan_id); safety_layer.simulate_execution(plan_id, session).await } async fn get_pending_decisions( _state: &Arc, task_id: &str, ) -> Result, Box> { trace!("Getting pending decisions for task_id={}", task_id); Ok(Vec::new()) } async fn submit_decision( _state: &Arc, task_id: &str, request: &DecisionRequest, ) -> Result<(), Box> { info!( "Submitting decision task_id={} decision_id={}", task_id, request.decision_id ); Ok(()) } async fn get_pending_approvals( _state: &Arc, task_id: &str, ) -> Result, Box> { trace!("Getting pending approvals for task_id={}", task_id); Ok(Vec::new()) } async fn submit_approval( _state: &Arc, task_id: &str, request: &ApprovalRequest, ) -> Result<(), Box> { info!( "Submitting approval task_id={} approval_id={} action={}", task_id, request.approval_id, request.action ); Ok(()) } fn render_task_list_html(tasks: &[AutoTask]) -> String { if tasks.is_empty() { return r#"

No tasks found

"#.to_string(); } let mut html = String::from(r#"
"#); for task in tasks { html.push_str(&format!( r#"
{}
{}
{}%
"#, html_escape(&task.id), html_escape(&task.title), html_escape(&task.status.to_string()), (task.progress * 100.0) as i32 )); } html.push_str("
"); html } fn html_escape(s: &str) -> String { s.replace('&', "&") .replace('<', "<") .replace('>', ">") .replace('"', """) .replace('\'', "'") }