2025-11-27 13:53:16 -03:00
|
|
|
|
pub mod scheduler;
|
|
|
|
|
|
|
2025-11-29 16:29:28 -03:00
|
|
|
|
use crate::core::urls::ApiUrls;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
use axum::{
|
|
|
|
|
|
extract::{Path, Query, State},
|
|
|
|
|
|
http::StatusCode,
|
2025-11-30 23:48:08 -03:00
|
|
|
|
response::{IntoResponse, Json},
|
2025-11-22 22:55:35 -03:00
|
|
|
|
routing::{delete, get, post, put},
|
|
|
|
|
|
Router,
|
|
|
|
|
|
};
|
|
|
|
|
|
use chrono::{DateTime, Utc};
|
|
|
|
|
|
use diesel::prelude::*;
|
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2025-12-26 08:59:25 -03:00
|
|
|
|
use std::fmt::Write as FmtWrite;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
use tokio::sync::RwLock;
|
|
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
use crate::shared::state::AppState;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
use crate::shared::utils::DbPool;
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
pub use scheduler::TaskScheduler;
|
|
|
|
|
|
|
2025-11-27 09:38:50 -03:00
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct CreateTaskRequest {
|
|
|
|
|
|
pub title: String,
|
|
|
|
|
|
pub description: Option<String>,
|
|
|
|
|
|
pub assignee_id: Option<Uuid>,
|
|
|
|
|
|
pub reporter_id: Option<Uuid>,
|
|
|
|
|
|
pub project_id: Option<Uuid>,
|
|
|
|
|
|
pub priority: Option<String>,
|
|
|
|
|
|
pub due_date: Option<DateTime<Utc>>,
|
|
|
|
|
|
pub tags: Option<Vec<String>>,
|
|
|
|
|
|
pub estimated_hours: Option<f64>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct TaskFilters {
|
|
|
|
|
|
pub status: Option<String>,
|
|
|
|
|
|
pub priority: Option<String>,
|
|
|
|
|
|
pub assignee: Option<String>,
|
|
|
|
|
|
pub project_id: Option<Uuid>,
|
|
|
|
|
|
pub tag: Option<String>,
|
|
|
|
|
|
pub limit: Option<usize>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-22 22:55:35 -03:00
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct TaskUpdate {
|
|
|
|
|
|
pub title: Option<String>,
|
|
|
|
|
|
pub description: Option<String>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
pub status: Option<String>,
|
|
|
|
|
|
pub priority: Option<String>,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
pub assignee: Option<String>,
|
|
|
|
|
|
pub due_date: Option<DateTime<Utc>>,
|
|
|
|
|
|
pub tags: Option<Vec<String>>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Queryable, Insertable)]
|
|
|
|
|
|
#[diesel(table_name = crate::core::shared::models::schema::tasks)]
|
2025-11-22 22:55:35 -03:00
|
|
|
|
pub struct Task {
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
pub title: String,
|
|
|
|
|
|
pub description: Option<String>,
|
2025-12-23 18:40:58 -03:00
|
|
|
|
pub status: String,
|
|
|
|
|
|
pub priority: String,
|
|
|
|
|
|
pub assignee_id: Option<Uuid>,
|
|
|
|
|
|
pub reporter_id: Option<Uuid>,
|
|
|
|
|
|
pub project_id: Option<Uuid>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
pub due_date: Option<DateTime<Utc>>,
|
|
|
|
|
|
pub tags: Vec<String>,
|
|
|
|
|
|
pub dependencies: Vec<Uuid>,
|
2025-12-23 18:40:58 -03:00
|
|
|
|
pub estimated_hours: Option<f64>,
|
|
|
|
|
|
pub actual_hours: Option<f64>,
|
|
|
|
|
|
pub progress: i32,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
pub created_at: DateTime<Utc>,
|
|
|
|
|
|
pub updated_at: DateTime<Utc>,
|
|
|
|
|
|
pub completed_at: Option<DateTime<Utc>>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct TaskResponse {
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
pub title: String,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
pub description: String,
|
2025-12-23 18:40:58 -03:00
|
|
|
|
pub assignee: Option<String>,
|
|
|
|
|
|
pub reporter: Option<String>,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
pub status: String,
|
|
|
|
|
|
pub priority: String,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
pub due_date: Option<DateTime<Utc>>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
pub estimated_hours: Option<f64>,
|
|
|
|
|
|
pub actual_hours: Option<f64>,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
pub tags: Vec<String>,
|
2025-12-23 18:40:58 -03:00
|
|
|
|
pub parent_task_id: Option<Uuid>,
|
|
|
|
|
|
pub subtasks: Vec<Uuid>,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
pub dependencies: Vec<Uuid>,
|
2025-12-23 18:40:58 -03:00
|
|
|
|
pub attachments: Vec<String>,
|
|
|
|
|
|
pub comments: Vec<TaskComment>,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
pub created_at: DateTime<Utc>,
|
|
|
|
|
|
pub updated_at: DateTime<Utc>,
|
|
|
|
|
|
pub completed_at: Option<DateTime<Utc>>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
pub progress: i32,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
impl From<Task> for TaskResponse {
|
|
|
|
|
|
fn from(task: Task) -> Self {
|
2025-12-26 08:59:25 -03:00
|
|
|
|
Self {
|
2025-11-27 08:34:24 -03:00
|
|
|
|
id: task.id,
|
|
|
|
|
|
title: task.title,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
description: task.description.unwrap_or_default(),
|
2025-11-27 08:34:24 -03:00
|
|
|
|
assignee: task.assignee_id.map(|id| id.to_string()),
|
2025-11-27 13:53:16 -03:00
|
|
|
|
reporter: task.reporter_id.map(|id| id.to_string()),
|
|
|
|
|
|
status: task.status,
|
|
|
|
|
|
priority: task.priority,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
due_date: task.due_date,
|
|
|
|
|
|
estimated_hours: task.estimated_hours,
|
|
|
|
|
|
actual_hours: task.actual_hours,
|
|
|
|
|
|
tags: task.tags,
|
2025-12-23 18:40:58 -03:00
|
|
|
|
parent_task_id: None,
|
|
|
|
|
|
subtasks: vec![],
|
2025-11-27 08:34:24 -03:00
|
|
|
|
dependencies: task.dependencies,
|
2025-12-23 18:40:58 -03:00
|
|
|
|
attachments: vec![],
|
|
|
|
|
|
comments: vec![],
|
2025-11-27 08:34:24 -03:00
|
|
|
|
created_at: task.created_at,
|
|
|
|
|
|
updated_at: task.updated_at,
|
|
|
|
|
|
completed_at: task.completed_at,
|
|
|
|
|
|
progress: task.progress,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 08:59:25 -03:00
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
2025-11-22 22:55:35 -03:00
|
|
|
|
pub enum TaskStatus {
|
|
|
|
|
|
Todo,
|
|
|
|
|
|
InProgress,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
Completed,
|
|
|
|
|
|
OnHold,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
Review,
|
|
|
|
|
|
Blocked,
|
|
|
|
|
|
Cancelled,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
Done,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
#[serde(rename_all = "lowercase")]
|
|
|
|
|
|
pub enum TaskPriority {
|
|
|
|
|
|
Low,
|
|
|
|
|
|
Medium,
|
|
|
|
|
|
High,
|
|
|
|
|
|
Urgent,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct TaskComment {
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
pub task_id: Uuid,
|
|
|
|
|
|
pub author: String,
|
|
|
|
|
|
pub content: String,
|
|
|
|
|
|
pub created_at: DateTime<Utc>,
|
|
|
|
|
|
pub updated_at: Option<DateTime<Utc>>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct TaskTemplate {
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
pub name: String,
|
|
|
|
|
|
pub description: Option<String>,
|
|
|
|
|
|
pub default_assignee: Option<String>,
|
|
|
|
|
|
pub default_priority: TaskPriority,
|
|
|
|
|
|
pub default_tags: Vec<String>,
|
|
|
|
|
|
pub checklist: Vec<ChecklistItem>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct ChecklistItem {
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
pub task_id: Uuid,
|
|
|
|
|
|
pub description: String,
|
|
|
|
|
|
pub completed: bool,
|
|
|
|
|
|
pub completed_by: Option<String>,
|
|
|
|
|
|
pub completed_at: Option<DateTime<Utc>>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct TaskBoard {
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
pub name: String,
|
|
|
|
|
|
pub description: Option<String>,
|
|
|
|
|
|
pub columns: Vec<BoardColumn>,
|
|
|
|
|
|
pub owner: String,
|
|
|
|
|
|
pub members: Vec<String>,
|
|
|
|
|
|
pub created_at: DateTime<Utc>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct BoardColumn {
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
pub name: String,
|
|
|
|
|
|
pub position: i32,
|
|
|
|
|
|
pub status_mapping: TaskStatus,
|
|
|
|
|
|
pub task_ids: Vec<Uuid>,
|
|
|
|
|
|
pub wip_limit: Option<i32>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
#[derive(Debug)]
|
2025-11-22 22:55:35 -03:00
|
|
|
|
pub struct TaskEngine {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
_db: DbPool,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
cache: Arc<RwLock<Vec<Task>>>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl TaskEngine {
|
2025-11-27 13:53:00 -03:00
|
|
|
|
pub fn new(db: DbPool) -> Self {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
Self {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
_db: db,
|
2025-11-27 09:38:50 -03:00
|
|
|
|
cache: Arc::new(RwLock::new(vec![])),
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 09:38:50 -03:00
|
|
|
|
pub async fn create_task(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
request: CreateTaskRequest,
|
|
|
|
|
|
) -> Result<TaskResponse, Box<dyn std::error::Error>> {
|
|
|
|
|
|
let id = Uuid::new_v4();
|
|
|
|
|
|
let now = Utc::now();
|
2025-11-27 08:34:24 -03:00
|
|
|
|
|
2025-11-27 09:38:50 -03:00
|
|
|
|
let task = Task {
|
|
|
|
|
|
id,
|
|
|
|
|
|
title: request.title,
|
|
|
|
|
|
description: request.description,
|
|
|
|
|
|
status: "todo".to_string(),
|
2025-12-26 08:59:25 -03:00
|
|
|
|
priority: request.priority.unwrap_or_else(|| "medium".to_string()),
|
2025-11-27 09:38:50 -03:00
|
|
|
|
assignee_id: request.assignee_id,
|
|
|
|
|
|
reporter_id: request.reporter_id,
|
|
|
|
|
|
project_id: request.project_id,
|
|
|
|
|
|
due_date: request.due_date,
|
|
|
|
|
|
tags: request.tags.unwrap_or_default(),
|
|
|
|
|
|
dependencies: vec![],
|
|
|
|
|
|
estimated_hours: request.estimated_hours,
|
|
|
|
|
|
actual_hours: None,
|
|
|
|
|
|
progress: 0,
|
|
|
|
|
|
created_at: now,
|
|
|
|
|
|
updated_at: now,
|
|
|
|
|
|
completed_at: None,
|
|
|
|
|
|
};
|
2025-11-27 08:34:24 -03:00
|
|
|
|
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
let created_task = self.create_task_with_db(task).await?;
|
2025-11-27 09:38:50 -03:00
|
|
|
|
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
Ok(created_task.into())
|
2025-11-27 09:38:50 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn list_tasks(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
filters: TaskFilters,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
) -> Result<Vec<TaskResponse>, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-27 09:38:50 -03:00
|
|
|
|
let cache = self.cache.read().await;
|
|
|
|
|
|
let mut tasks: Vec<Task> = cache.clone();
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-12-23 18:40:58 -03:00
|
|
|
|
|
2025-11-27 09:38:50 -03:00
|
|
|
|
if let Some(status) = filters.status {
|
|
|
|
|
|
tasks.retain(|t| t.status == status);
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(priority) = filters.priority {
|
|
|
|
|
|
tasks.retain(|t| t.priority == priority);
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(assignee) = filters.assignee {
|
|
|
|
|
|
if let Ok(assignee_id) = Uuid::parse_str(&assignee) {
|
|
|
|
|
|
tasks.retain(|t| t.assignee_id == Some(assignee_id));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(project_id) = filters.project_id {
|
|
|
|
|
|
tasks.retain(|t| t.project_id == Some(project_id));
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(tag) = filters.tag {
|
|
|
|
|
|
tasks.retain(|t| t.tags.contains(&tag));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tasks.sort_by(|a, b| b.created_at.cmp(&a.created_at));
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(limit) = filters.limit {
|
|
|
|
|
|
tasks.truncate(limit);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(tasks.into_iter().map(|t| t.into()).collect())
|
2025-11-27 08:34:24 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 09:38:50 -03:00
|
|
|
|
pub async fn update_status(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
id: Uuid,
|
|
|
|
|
|
status: String,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
) -> Result<TaskResponse, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-27 09:38:50 -03:00
|
|
|
|
let mut cache = self.cache.write().await;
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(task) = cache.iter_mut().find(|t| t.id == id) {
|
2025-12-26 08:59:25 -03:00
|
|
|
|
task.status.clone_from(&status);
|
2025-11-27 09:38:50 -03:00
|
|
|
|
if status == "completed" || status == "done" {
|
|
|
|
|
|
task.completed_at = Some(Utc::now());
|
|
|
|
|
|
task.progress = 100;
|
|
|
|
|
|
}
|
|
|
|
|
|
task.updated_at = Utc::now();
|
|
|
|
|
|
Ok(task.clone().into())
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Err("Task not found".into())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_create(
|
|
|
|
|
|
State(state): State<Arc<AppState>>,
|
|
|
|
|
|
Json(payload): Json<CreateTaskRequest>,
|
|
|
|
|
|
) -> Result<Json<TaskResponse>, StatusCode> {
|
2025-11-27 13:53:00 -03:00
|
|
|
|
let task_engine = &state.task_engine;
|
2025-11-27 09:38:50 -03:00
|
|
|
|
|
|
|
|
|
|
match task_engine.create_task(payload).await {
|
|
|
|
|
|
Ok(task) => Ok(Json(task)),
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
log::error!("Failed to create task: {}", e);
|
|
|
|
|
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_update(
|
|
|
|
|
|
State(state): State<Arc<AppState>>,
|
|
|
|
|
|
Path(id): Path<Uuid>,
|
|
|
|
|
|
Json(payload): Json<TaskUpdate>,
|
|
|
|
|
|
) -> Result<Json<TaskResponse>, StatusCode> {
|
2025-11-27 13:53:00 -03:00
|
|
|
|
let task_engine = &state.task_engine;
|
2025-11-27 09:38:50 -03:00
|
|
|
|
|
|
|
|
|
|
match task_engine.update_task(id, payload).await {
|
2025-11-27 13:53:00 -03:00
|
|
|
|
Ok(task) => Ok(Json(task.into())),
|
2025-11-27 09:38:50 -03:00
|
|
|
|
Err(e) => {
|
|
|
|
|
|
log::error!("Failed to update task: {}", e);
|
|
|
|
|
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_delete(
|
|
|
|
|
|
State(state): State<Arc<AppState>>,
|
|
|
|
|
|
Path(id): Path<Uuid>,
|
|
|
|
|
|
) -> Result<StatusCode, StatusCode> {
|
2025-11-27 13:53:00 -03:00
|
|
|
|
let task_engine = &state.task_engine;
|
2025-11-27 09:38:50 -03:00
|
|
|
|
|
|
|
|
|
|
match task_engine.delete_task(id).await {
|
|
|
|
|
|
Ok(_) => Ok(StatusCode::NO_CONTENT),
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
log::error!("Failed to delete task: {}", e);
|
|
|
|
|
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_get(
|
|
|
|
|
|
State(state): State<Arc<AppState>>,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
Path(id): Path<String>,
|
|
|
|
|
|
) -> impl IntoResponse {
|
|
|
|
|
|
let conn = state.conn.clone();
|
|
|
|
|
|
let task_id = id.clone();
|
2025-11-27 09:38:50 -03:00
|
|
|
|
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
let result = tokio::task::spawn_blocking(move || {
|
|
|
|
|
|
let mut db_conn = conn
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.map_err(|e| format!("DB connection error: {}", e))?;
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, QueryableByName, serde::Serialize)]
|
|
|
|
|
|
struct AutoTaskRow {
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Uuid)]
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Text)]
|
|
|
|
|
|
pub title: String,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Text)]
|
|
|
|
|
|
pub status: String,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Text)]
|
|
|
|
|
|
pub priority: String,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Text>)]
|
|
|
|
|
|
pub intent: Option<String>,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Text>)]
|
|
|
|
|
|
pub error: Option<String>,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Float)]
|
|
|
|
|
|
pub progress: f32,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Timestamptz)]
|
|
|
|
|
|
pub created_at: chrono::DateTime<chrono::Utc>,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>)]
|
|
|
|
|
|
pub completed_at: Option<chrono::DateTime<chrono::Utc>>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let parsed_uuid = match Uuid::parse_str(&task_id) {
|
|
|
|
|
|
Ok(u) => u,
|
|
|
|
|
|
Err(_) => return Err(format!("Invalid task ID: {}", task_id)),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let task: Option<AutoTaskRow> = diesel::sql_query(
|
|
|
|
|
|
"SELECT id, title, status, priority, intent, error, progress, created_at, completed_at
|
|
|
|
|
|
FROM auto_tasks WHERE id = $1 LIMIT 1"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind::<diesel::sql_types::Uuid, _>(parsed_uuid)
|
|
|
|
|
|
.get_result(&mut db_conn)
|
|
|
|
|
|
.ok();
|
|
|
|
|
|
|
|
|
|
|
|
Ok::<_, String>(task)
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
|
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
|
|
log::error!("Task query failed: {}", e);
|
|
|
|
|
|
Err(format!("Task query failed: {}", e))
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
match result {
|
|
|
|
|
|
Ok(Some(task)) => {
|
|
|
|
|
|
let status_class = match task.status.as_str() {
|
|
|
|
|
|
"completed" | "done" => "completed",
|
|
|
|
|
|
"running" | "pending" => "running",
|
|
|
|
|
|
"failed" | "error" => "error",
|
|
|
|
|
|
_ => "pending"
|
|
|
|
|
|
};
|
|
|
|
|
|
let progress_percent = (task.progress * 100.0) as u8;
|
|
|
|
|
|
let created = task.created_at.format("%Y-%m-%d %H:%M").to_string();
|
|
|
|
|
|
let completed = task.completed_at.map(|d| d.format("%Y-%m-%d %H:%M").to_string()).unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
|
|
let html = format!(r#"
|
|
|
|
|
|
<div class="task-detail-header">
|
|
|
|
|
|
<h2 class="task-detail-title">{}</h2>
|
|
|
|
|
|
<span class="task-status task-status-{}">{}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="task-detail-meta">
|
|
|
|
|
|
<div class="meta-item"><span class="meta-label">Priority:</span> <span class="meta-value">{}</span></div>
|
|
|
|
|
|
<div class="meta-item"><span class="meta-label">Created:</span> <span class="meta-value">{}</span></div>
|
|
|
|
|
|
{}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="task-detail-progress">
|
|
|
|
|
|
<div class="progress-label">Progress: {}%</div>
|
|
|
|
|
|
<div class="progress-bar-container">
|
|
|
|
|
|
<div class="progress-bar-fill" style="width: {}%"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{}
|
|
|
|
|
|
{}
|
|
|
|
|
|
"#,
|
|
|
|
|
|
task.title,
|
|
|
|
|
|
status_class,
|
|
|
|
|
|
task.status,
|
|
|
|
|
|
task.priority,
|
|
|
|
|
|
created,
|
|
|
|
|
|
if !completed.is_empty() { format!(r#"<div class="meta-item"><span class="meta-label">Completed:</span> <span class="meta-value">{}</span></div>"#, completed) } else { String::new() },
|
|
|
|
|
|
progress_percent,
|
|
|
|
|
|
progress_percent,
|
|
|
|
|
|
task.intent.map(|i| format!(r#"<div class="task-detail-section"><h3>Intent</h3><p class="intent-text">{}</p></div>"#, i)).unwrap_or_default(),
|
|
|
|
|
|
task.error.map(|e| format!(r#"<div class="task-detail-section error-section"><h3>Error</h3><p class="error-text">{}</p></div>"#, e)).unwrap_or_default()
|
|
|
|
|
|
);
|
|
|
|
|
|
(StatusCode::OK, axum::response::Html(html)).into_response()
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(None) => {
|
|
|
|
|
|
(StatusCode::NOT_FOUND, axum::response::Html("<div class='error'>Task not found</div>".to_string())).into_response()
|
|
|
|
|
|
}
|
2025-11-27 09:38:50 -03:00
|
|
|
|
Err(e) => {
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
(StatusCode::INTERNAL_SERVER_ERROR, axum::response::Html(format!("<div class='error'>{}</div>", e))).into_response()
|
2025-11-27 09:38:50 -03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl TaskEngine {
|
|
|
|
|
|
pub async fn create_task_with_db(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
task: Task,
|
|
|
|
|
|
) -> Result<Task, Box<dyn std::error::Error>> {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
use crate::shared::models::schema::tasks::dsl::*;
|
|
|
|
|
|
use diesel::prelude::*;
|
|
|
|
|
|
|
|
|
|
|
|
let conn = self._db.clone();
|
|
|
|
|
|
let task_clone = task.clone();
|
|
|
|
|
|
|
|
|
|
|
|
let created_task =
|
|
|
|
|
|
tokio::task::spawn_blocking(move || -> Result<Task, diesel::result::Error> {
|
|
|
|
|
|
let mut db_conn = conn.get().map_err(|e| {
|
|
|
|
|
|
diesel::result::Error::DatabaseError(
|
|
|
|
|
|
diesel::result::DatabaseErrorKind::UnableToSendCommand,
|
|
|
|
|
|
Box::new(e.to_string()),
|
|
|
|
|
|
)
|
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
|
|
diesel::insert_into(tasks)
|
|
|
|
|
|
.values(&task_clone)
|
|
|
|
|
|
.get_result(&mut db_conn)
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
|
|
|
|
|
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?
|
|
|
|
|
|
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
|
|
let mut cache = self.cache.write().await;
|
|
|
|
|
|
cache.push(created_task.clone());
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
|
|
Ok(created_task)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn update_task(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
id: Uuid,
|
|
|
|
|
|
updates: TaskUpdate,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
) -> Result<Task, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
let updated_at = Utc::now();
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
let mut cache = self.cache.write().await;
|
|
|
|
|
|
if let Some(task) = cache.iter_mut().find(|t| t.id == id) {
|
|
|
|
|
|
task.updated_at = updated_at;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
if let Some(title) = updates.title {
|
|
|
|
|
|
task.title = title;
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(description) = updates.description {
|
|
|
|
|
|
task.description = Some(description);
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(status) = updates.status {
|
2025-12-26 08:59:25 -03:00
|
|
|
|
task.status.clone_from(&status);
|
2025-11-27 13:53:16 -03:00
|
|
|
|
if status == "completed" || status == "done" {
|
|
|
|
|
|
task.completed_at = Some(Utc::now());
|
|
|
|
|
|
task.progress = 100;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(priority) = updates.priority {
|
|
|
|
|
|
task.priority = priority;
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(assignee) = updates.assignee {
|
|
|
|
|
|
task.assignee_id = Uuid::parse_str(&assignee).ok();
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(due_date) = updates.due_date {
|
|
|
|
|
|
task.due_date = Some(due_date);
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(tags) = updates.tags {
|
|
|
|
|
|
task.tags = tags;
|
|
|
|
|
|
}
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
2025-12-26 08:59:25 -03:00
|
|
|
|
let result = task.clone();
|
|
|
|
|
|
drop(cache);
|
|
|
|
|
|
return Ok(result);
|
2025-11-27 13:53:16 -03:00
|
|
|
|
}
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
Err("Task not found".into())
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
pub async fn delete_task(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
id: Uuid,
|
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
let dependencies = self.get_task_dependencies(id).await?;
|
|
|
|
|
|
if !dependencies.is_empty() {
|
|
|
|
|
|
return Err("Cannot delete task with dependencies".into());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
let mut cache = self.cache.write().await;
|
|
|
|
|
|
cache.retain(|t| t.id != id);
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-12-23 18:40:58 -03:00
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
self.refresh_cache()
|
|
|
|
|
|
.await
|
|
|
|
|
|
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
2025-12-26 08:59:25 -03:00
|
|
|
|
Box::new(std::io::Error::other(e.to_string()))
|
2025-11-27 13:53:16 -03:00
|
|
|
|
})?;
|
|
|
|
|
|
Ok(())
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn get_user_tasks(
|
|
|
|
|
|
&self,
|
2025-11-27 23:10:43 -03:00
|
|
|
|
user_id: Uuid,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
) -> Result<Vec<Task>, Box<dyn std::error::Error>> {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
let cache = self.cache.read().await;
|
|
|
|
|
|
let user_tasks: Vec<Task> = cache
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.filter(|t| {
|
|
|
|
|
|
t.assignee_id.map(|a| a == user_id).unwrap_or(false)
|
|
|
|
|
|
|| t.reporter_id.map(|r| r == user_id).unwrap_or(false)
|
|
|
|
|
|
})
|
|
|
|
|
|
.cloned()
|
|
|
|
|
|
.collect();
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
Ok(user_tasks)
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn get_tasks_by_status(
|
|
|
|
|
|
&self,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
status: TaskStatus,
|
|
|
|
|
|
) -> Result<Vec<Task>, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
|
let cache = self.cache.read().await;
|
|
|
|
|
|
let status_str = format!("{:?}", status);
|
|
|
|
|
|
let mut tasks: Vec<Task> = cache
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.filter(|t| t.status == status_str)
|
|
|
|
|
|
.cloned()
|
|
|
|
|
|
.collect();
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-11-27 13:53:16 -03:00
|
|
|
|
tasks.sort_by(|a, b| b.created_at.cmp(&a.created_at));
|
2025-11-27 08:34:24 -03:00
|
|
|
|
Ok(tasks)
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
pub async fn get_overdue_tasks(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
) -> Result<Vec<Task>, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
let now = Utc::now();
|
2025-11-27 13:53:16 -03:00
|
|
|
|
let cache = self.cache.read().await;
|
|
|
|
|
|
let mut tasks: Vec<Task> = cache
|
|
|
|
|
|
.iter()
|
2025-12-26 08:59:25 -03:00
|
|
|
|
.filter(|t| t.due_date.is_some_and(|due| due < now) && t.status != "completed")
|
2025-11-27 13:53:16 -03:00
|
|
|
|
.cloned()
|
|
|
|
|
|
.collect();
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-11-27 13:53:16 -03:00
|
|
|
|
tasks.sort_by(|a, b| a.due_date.cmp(&b.due_date));
|
2025-11-27 08:34:24 -03:00
|
|
|
|
Ok(tasks)
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 08:59:25 -03:00
|
|
|
|
pub fn add_comment(
|
2025-11-22 22:55:35 -03:00
|
|
|
|
&self,
|
|
|
|
|
|
task_id: Uuid,
|
|
|
|
|
|
author: &str,
|
|
|
|
|
|
content: &str,
|
|
|
|
|
|
) -> Result<TaskComment, Box<dyn std::error::Error>> {
|
|
|
|
|
|
let comment = TaskComment {
|
|
|
|
|
|
id: Uuid::new_v4(),
|
|
|
|
|
|
task_id,
|
|
|
|
|
|
author: author.to_string(),
|
|
|
|
|
|
content: content.to_string(),
|
|
|
|
|
|
created_at: Utc::now(),
|
|
|
|
|
|
updated_at: None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
log::info!("Added comment to task {}: {}", task_id, content);
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
|
|
Ok(comment)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn create_subtask(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
parent_id: Uuid,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
subtask_data: CreateTaskRequest,
|
|
|
|
|
|
) -> Result<Task, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
|
{
|
|
|
|
|
|
let cache = self.cache.read().await;
|
|
|
|
|
|
if !cache.iter().any(|t| t.id == parent_id) {
|
|
|
|
|
|
return Err(Box::new(std::io::Error::new(
|
|
|
|
|
|
std::io::ErrorKind::NotFound,
|
|
|
|
|
|
"Parent task not found",
|
|
|
|
|
|
))
|
|
|
|
|
|
as Box<dyn std::error::Error + Send + Sync>);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
let subtask = self.create_task(subtask_data).await.map_err(
|
|
|
|
|
|
|e| -> Box<dyn std::error::Error + Send + Sync> {
|
2025-12-26 08:59:25 -03:00
|
|
|
|
Box::new(std::io::Error::other(e.to_string()))
|
2025-11-27 13:53:16 -03:00
|
|
|
|
},
|
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
|
|
let created = Task {
|
|
|
|
|
|
id: subtask.id,
|
|
|
|
|
|
title: subtask.title,
|
|
|
|
|
|
description: Some(subtask.description),
|
|
|
|
|
|
status: subtask.status,
|
|
|
|
|
|
priority: subtask.priority,
|
|
|
|
|
|
assignee_id: subtask
|
|
|
|
|
|
.assignee
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
.and_then(|a| Uuid::parse_str(a).ok()),
|
|
|
|
|
|
reporter_id: subtask
|
|
|
|
|
|
.reporter
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
.and_then(|r| Uuid::parse_str(r).ok()),
|
|
|
|
|
|
project_id: None,
|
|
|
|
|
|
due_date: subtask.due_date,
|
|
|
|
|
|
tags: subtask.tags,
|
|
|
|
|
|
dependencies: subtask.dependencies,
|
|
|
|
|
|
estimated_hours: subtask.estimated_hours,
|
|
|
|
|
|
actual_hours: subtask.actual_hours,
|
|
|
|
|
|
progress: subtask.progress,
|
|
|
|
|
|
created_at: subtask.created_at,
|
|
|
|
|
|
updated_at: subtask.updated_at,
|
|
|
|
|
|
completed_at: subtask.completed_at,
|
|
|
|
|
|
};
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
|
|
Ok(created)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn get_task_dependencies(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
task_id: Uuid,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
) -> Result<Vec<Task>, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
let task = self.get_task(task_id).await?;
|
|
|
|
|
|
let mut dependencies = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
for dep_id in task.dependencies {
|
|
|
|
|
|
if let Ok(dep_task) = self.get_task(dep_id).await {
|
|
|
|
|
|
dependencies.push(dep_task);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(dependencies)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
pub async fn get_task(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
id: Uuid,
|
|
|
|
|
|
) -> Result<Task, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
|
let cache = self.cache.read().await;
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
if let Some(task) = cache.iter().find(|t| t.id == id).cloned() {
|
|
|
|
|
|
drop(cache);
|
|
|
|
|
|
return Ok(task);
|
|
|
|
|
|
}
|
|
|
|
|
|
drop(cache);
|
|
|
|
|
|
|
|
|
|
|
|
let conn = self._db.clone();
|
|
|
|
|
|
let task_id = id;
|
|
|
|
|
|
|
|
|
|
|
|
let task = tokio::task::spawn_blocking(move || {
|
|
|
|
|
|
use crate::shared::models::schema::tasks::dsl::*;
|
|
|
|
|
|
use diesel::prelude::*;
|
|
|
|
|
|
|
|
|
|
|
|
let mut db_conn = conn.get().map_err(|e| {
|
|
|
|
|
|
Box::<dyn std::error::Error + Send + Sync>::from(format!("DB error: {e}"))
|
2025-11-27 13:53:16 -03:00
|
|
|
|
})?;
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
|
|
|
|
|
|
tasks
|
|
|
|
|
|
.filter(id.eq(task_id))
|
|
|
|
|
|
.first::<Task>(&mut db_conn)
|
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
|
Box::<dyn std::error::Error + Send + Sync>::from(format!("Task not found: {e}"))
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
|
Box::<dyn std::error::Error + Send + Sync>::from(format!("Task error: {e}"))
|
|
|
|
|
|
})??;
|
|
|
|
|
|
|
|
|
|
|
|
let mut cache = self.cache.write().await;
|
|
|
|
|
|
cache.push(task.clone());
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-11-27 08:34:24 -03:00
|
|
|
|
|
|
|
|
|
|
Ok(task)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
pub async fn get_all_tasks(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
) -> Result<Vec<Task>, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
|
let cache = self.cache.read().await;
|
|
|
|
|
|
let mut tasks: Vec<Task> = cache.clone();
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-11-27 13:53:16 -03:00
|
|
|
|
tasks.sort_by(|a, b| b.created_at.cmp(&a.created_at));
|
2025-11-27 08:34:24 -03:00
|
|
|
|
Ok(tasks)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn assign_task(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
id: Uuid,
|
|
|
|
|
|
assignee: String,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
) -> Result<Task, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-27 08:34:24 -03:00
|
|
|
|
let assignee_id = Uuid::parse_str(&assignee).ok();
|
|
|
|
|
|
let updated_at = Utc::now();
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
let mut cache = self.cache.write().await;
|
|
|
|
|
|
if let Some(task) = cache.iter_mut().find(|t| t.id == id) {
|
|
|
|
|
|
task.assignee_id = assignee_id;
|
|
|
|
|
|
task.updated_at = updated_at;
|
2025-12-26 08:59:25 -03:00
|
|
|
|
let result = task.clone();
|
|
|
|
|
|
drop(cache);
|
|
|
|
|
|
return Ok(result);
|
2025-11-27 13:53:16 -03:00
|
|
|
|
}
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-11-27 08:34:24 -03:00
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
Err("Task not found".into())
|
2025-11-27 08:34:24 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn set_dependencies(
|
|
|
|
|
|
&self,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
task_id: Uuid,
|
|
|
|
|
|
dependency_ids: Vec<Uuid>,
|
|
|
|
|
|
) -> Result<TaskResponse, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
|
let mut cache = self.cache.write().await;
|
|
|
|
|
|
if let Some(task) = cache.iter_mut().find(|t| t.id == task_id) {
|
|
|
|
|
|
task.dependencies = dependency_ids;
|
|
|
|
|
|
task.updated_at = Utc::now();
|
|
|
|
|
|
}
|
2025-12-23 18:40:58 -03:00
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
let task = self.get_task(task_id).await?;
|
|
|
|
|
|
Ok(task.into())
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 22:54:22 -03:00
|
|
|
|
pub async fn calculate_progress(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
task_id: Uuid,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
) -> Result<u8, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
let task = self.get_task(task_id).await?;
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
Ok(match task.status.as_str() {
|
2025-11-27 13:53:16 -03:00
|
|
|
|
"in_progress" | "in-progress" => 50,
|
|
|
|
|
|
"review" => 75,
|
|
|
|
|
|
"completed" | "done" => 100,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
"blocked" => {
|
2025-11-27 13:53:16 -03:00
|
|
|
|
((task.actual_hours.unwrap_or(0.0) / task.estimated_hours.unwrap_or(1.0)) * 100.0)
|
|
|
|
|
|
as u8
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
// "todo", "cancelled", and any other status default to 0
|
2025-11-27 13:53:16 -03:00
|
|
|
|
_ => 0,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
})
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn create_from_template(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
_template_id: Uuid,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
assignee_id: Option<Uuid>,
|
|
|
|
|
|
) -> Result<Task, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
let template = TaskTemplate {
|
|
|
|
|
|
id: Uuid::new_v4(),
|
|
|
|
|
|
name: "Default Template".to_string(),
|
|
|
|
|
|
description: Some("Default template".to_string()),
|
|
|
|
|
|
default_assignee: None,
|
|
|
|
|
|
default_priority: TaskPriority::Medium,
|
|
|
|
|
|
default_tags: vec![],
|
|
|
|
|
|
checklist: vec![],
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
let now = Utc::now();
|
2025-11-22 22:55:35 -03:00
|
|
|
|
let task = Task {
|
|
|
|
|
|
id: Uuid::new_v4(),
|
2025-11-27 13:53:16 -03:00
|
|
|
|
title: format!("Task from template: {}", template.name),
|
|
|
|
|
|
description: template.description.clone(),
|
2025-11-27 08:34:24 -03:00
|
|
|
|
status: "todo".to_string(),
|
|
|
|
|
|
priority: "medium".to_string(),
|
2025-11-27 15:19:17 -03:00
|
|
|
|
assignee_id,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
reporter_id: Some(Uuid::new_v4()),
|
2025-11-27 08:34:24 -03:00
|
|
|
|
project_id: None,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
due_date: None,
|
|
|
|
|
|
estimated_hours: None,
|
|
|
|
|
|
actual_hours: None,
|
|
|
|
|
|
tags: template.default_tags,
|
|
|
|
|
|
dependencies: Vec::new(),
|
2025-11-27 08:34:24 -03:00
|
|
|
|
progress: 0,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
created_at: now,
|
|
|
|
|
|
updated_at: now,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
completed_at: None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 13:53:00 -03:00
|
|
|
|
let task_request = CreateTaskRequest {
|
|
|
|
|
|
title: task.title,
|
|
|
|
|
|
description: task.description,
|
|
|
|
|
|
assignee_id: task.assignee_id,
|
|
|
|
|
|
reporter_id: task.reporter_id,
|
|
|
|
|
|
project_id: task.project_id,
|
|
|
|
|
|
priority: Some(task.priority),
|
|
|
|
|
|
due_date: task.due_date,
|
|
|
|
|
|
tags: Some(task.tags),
|
|
|
|
|
|
estimated_hours: task.estimated_hours,
|
|
|
|
|
|
};
|
2025-11-27 13:53:16 -03:00
|
|
|
|
let created = self.create_task(task_request).await.map_err(
|
|
|
|
|
|
|e| -> Box<dyn std::error::Error + Send + Sync> {
|
2025-12-26 08:59:25 -03:00
|
|
|
|
Box::new(std::io::Error::other(e.to_string()))
|
2025-11-27 13:53:16 -03:00
|
|
|
|
},
|
|
|
|
|
|
)?;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
|
|
for item in template.checklist {
|
|
|
|
|
|
let _checklist_item = ChecklistItem {
|
|
|
|
|
|
id: Uuid::new_v4(),
|
|
|
|
|
|
task_id: created.id,
|
2025-11-27 23:10:43 -03:00
|
|
|
|
description: item.description.clone(),
|
2025-11-22 22:55:35 -03:00
|
|
|
|
completed: false,
|
|
|
|
|
|
completed_by: None,
|
|
|
|
|
|
completed_at: None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
log::info!(
|
|
|
|
|
|
"Added checklist item to task {}: {}",
|
|
|
|
|
|
created.id,
|
|
|
|
|
|
item.description
|
|
|
|
|
|
);
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 13:53:00 -03:00
|
|
|
|
let task = Task {
|
|
|
|
|
|
id: created.id,
|
|
|
|
|
|
title: created.title,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
description: Some(created.description),
|
|
|
|
|
|
status: created.status,
|
|
|
|
|
|
priority: created.priority,
|
|
|
|
|
|
assignee_id: created
|
|
|
|
|
|
.assignee
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
.and_then(|a| Uuid::parse_str(a).ok()),
|
|
|
|
|
|
reporter_id: created.reporter.as_ref().and_then(|r| {
|
|
|
|
|
|
if r == "system" {
|
|
|
|
|
|
None
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Uuid::parse_str(r).ok()
|
|
|
|
|
|
}
|
|
|
|
|
|
}),
|
2025-11-27 13:53:00 -03:00
|
|
|
|
project_id: None,
|
|
|
|
|
|
tags: created.tags,
|
|
|
|
|
|
dependencies: created.dependencies,
|
|
|
|
|
|
due_date: created.due_date,
|
|
|
|
|
|
estimated_hours: created.estimated_hours,
|
|
|
|
|
|
actual_hours: created.actual_hours,
|
|
|
|
|
|
progress: created.progress,
|
|
|
|
|
|
created_at: created.created_at,
|
|
|
|
|
|
updated_at: created.updated_at,
|
|
|
|
|
|
completed_at: created.completed_at,
|
|
|
|
|
|
};
|
|
|
|
|
|
Ok(task)
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
2025-12-23 18:40:58 -03:00
|
|
|
|
|
2025-12-26 08:59:25 -03:00
|
|
|
|
fn _notify_assignee(assignee: &str, task: &Task) -> Result<(), Box<dyn std::error::Error>> {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
log::info!(
|
|
|
|
|
|
"Notifying {} about new task assignment: {}",
|
|
|
|
|
|
assignee,
|
|
|
|
|
|
task.title
|
|
|
|
|
|
);
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
async fn refresh_cache(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
use crate::shared::models::schema::tasks::dsl::*;
|
|
|
|
|
|
use diesel::prelude::*;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
let conn = self._db.clone();
|
|
|
|
|
|
|
|
|
|
|
|
let task_list = tokio::task::spawn_blocking(
|
|
|
|
|
|
move || -> Result<Vec<Task>, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
|
let mut db_conn = conn.get()?;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
tasks
|
|
|
|
|
|
.order(created_at.desc())
|
|
|
|
|
|
.load::<Task>(&mut db_conn)
|
|
|
|
|
|
.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
|
|
|
|
|
|
},
|
|
|
|
|
|
)
|
|
|
|
|
|
.await??;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
|
|
let mut cache = self.cache.write().await;
|
2025-11-27 23:10:43 -03:00
|
|
|
|
*cache = task_list;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn get_statistics(
|
|
|
|
|
|
&self,
|
2025-11-27 13:53:16 -03:00
|
|
|
|
user_id: Option<Uuid>,
|
|
|
|
|
|
) -> Result<serde_json::Value, Box<dyn std::error::Error + Send + Sync>> {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
use chrono::Utc;
|
|
|
|
|
|
|
|
|
|
|
|
let cache = self.cache.read().await;
|
2025-12-26 08:59:25 -03:00
|
|
|
|
let task_list = if let Some(uid) = user_id {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
cache
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.filter(|t| {
|
|
|
|
|
|
t.assignee_id.map(|a| a == uid).unwrap_or(false)
|
|
|
|
|
|
|| t.reporter_id.map(|r| r == uid).unwrap_or(false)
|
|
|
|
|
|
})
|
|
|
|
|
|
.cloned()
|
|
|
|
|
|
.collect()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cache.clone()
|
|
|
|
|
|
};
|
2025-12-26 08:59:25 -03:00
|
|
|
|
drop(cache);
|
2025-12-23 18:40:58 -03:00
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
let mut todo_count = 0;
|
|
|
|
|
|
let mut in_progress_count = 0;
|
|
|
|
|
|
let mut done_count = 0;
|
|
|
|
|
|
let mut overdue_count = 0;
|
|
|
|
|
|
let mut total_completion_ratio = 0.0;
|
|
|
|
|
|
let mut ratio_count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
let now = Utc::now();
|
|
|
|
|
|
|
|
|
|
|
|
for task in &task_list {
|
|
|
|
|
|
match task.status.as_str() {
|
|
|
|
|
|
"todo" => todo_count += 1,
|
|
|
|
|
|
"in_progress" => in_progress_count += 1,
|
|
|
|
|
|
"done" => done_count += 1,
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(due) = task.due_date {
|
|
|
|
|
|
if due < now && task.status != "done" {
|
|
|
|
|
|
overdue_count += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if let (Some(actual), Some(estimated)) = (task.actual_hours, task.estimated_hours) {
|
|
|
|
|
|
if estimated > 0.0 {
|
|
|
|
|
|
total_completion_ratio += actual / estimated;
|
|
|
|
|
|
ratio_count += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let avg_completion_ratio = if ratio_count > 0 {
|
2025-12-26 08:59:25 -03:00
|
|
|
|
Some(total_completion_ratio / f64::from(ratio_count))
|
2025-11-22 22:55:35 -03:00
|
|
|
|
} else {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
None
|
2025-11-22 22:55:35 -03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Ok(serde_json::json!({
|
2025-11-27 23:10:43 -03:00
|
|
|
|
"todo_count": todo_count,
|
|
|
|
|
|
"in_progress_count": in_progress_count,
|
|
|
|
|
|
"done_count": done_count,
|
|
|
|
|
|
"overdue_count": overdue_count,
|
|
|
|
|
|
"avg_completion_ratio": avg_completion_ratio,
|
|
|
|
|
|
"total_tasks": task_list.len()
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub mod handlers {
|
|
|
|
|
|
use super::*;
|
2025-11-26 22:54:22 -03:00
|
|
|
|
use axum::extract::{Path as AxumPath, Query as AxumQuery, State as AxumState};
|
2025-11-22 22:55:35 -03:00
|
|
|
|
use axum::http::StatusCode;
|
2025-11-26 22:54:22 -03:00
|
|
|
|
use axum::response::{IntoResponse, Json as AxumJson};
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
pub async fn create_task_handler(
|
|
|
|
|
|
AxumState(engine): AxumState<Arc<TaskEngine>>,
|
|
|
|
|
|
AxumJson(task_resp): AxumJson<TaskResponse>,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
) -> impl IntoResponse {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
let task = Task {
|
|
|
|
|
|
id: task_resp.id,
|
|
|
|
|
|
title: task_resp.title,
|
|
|
|
|
|
description: Some(task_resp.description),
|
|
|
|
|
|
assignee_id: task_resp.assignee.and_then(|s| Uuid::parse_str(&s).ok()),
|
|
|
|
|
|
reporter_id: task_resp.reporter.and_then(|s| Uuid::parse_str(&s).ok()),
|
|
|
|
|
|
project_id: None,
|
|
|
|
|
|
status: task_resp.status,
|
|
|
|
|
|
priority: task_resp.priority,
|
|
|
|
|
|
due_date: task_resp.due_date,
|
|
|
|
|
|
estimated_hours: task_resp.estimated_hours,
|
|
|
|
|
|
actual_hours: task_resp.actual_hours,
|
|
|
|
|
|
tags: task_resp.tags,
|
|
|
|
|
|
dependencies: vec![],
|
|
|
|
|
|
progress: 0,
|
|
|
|
|
|
created_at: task_resp.created_at,
|
|
|
|
|
|
updated_at: task_resp.updated_at,
|
|
|
|
|
|
completed_at: None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
match engine.create_task_with_db(task).await {
|
|
|
|
|
|
Ok(created) => (StatusCode::CREATED, AxumJson(serde_json::json!(created))),
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
log::error!("Failed to create task: {}", e);
|
|
|
|
|
|
(
|
|
|
|
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
AxumJson(serde_json::json!({"error": e.to_string()})),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
pub async fn get_tasks_handler(
|
|
|
|
|
|
AxumState(engine): AxumState<Arc<TaskEngine>>,
|
|
|
|
|
|
AxumQuery(query): AxumQuery<serde_json::Value>,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
) -> impl IntoResponse {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
let status_filter = query
|
|
|
|
|
|
.get("status")
|
|
|
|
|
|
.and_then(|v| v.as_str())
|
|
|
|
|
|
.and_then(|s| serde_json::from_str::<TaskStatus>(&format!("\"{}\"", s)).ok());
|
|
|
|
|
|
|
|
|
|
|
|
let user_id = query
|
|
|
|
|
|
.get("user_id")
|
|
|
|
|
|
.and_then(|v| v.as_str())
|
|
|
|
|
|
.and_then(|s| Uuid::parse_str(s).ok());
|
|
|
|
|
|
|
|
|
|
|
|
let tasks = if let Some(status) = status_filter {
|
|
|
|
|
|
match engine.get_tasks_by_status(status).await {
|
|
|
|
|
|
Ok(t) => t,
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
log::error!("Failed to get tasks by status: {}", e);
|
|
|
|
|
|
return (
|
|
|
|
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
AxumJson(serde_json::json!({"error": e.to_string()})),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if let Some(uid) = user_id {
|
|
|
|
|
|
match engine.get_user_tasks(uid).await {
|
|
|
|
|
|
Ok(t) => t,
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
log::error!("Failed to get user tasks: {}", e);
|
|
|
|
|
|
return (
|
|
|
|
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
AxumJson(serde_json::json!({"error": e.to_string()})),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
match engine.get_all_tasks().await {
|
|
|
|
|
|
Ok(t) => t,
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
log::error!("Failed to get all tasks: {}", e);
|
|
|
|
|
|
return (
|
|
|
|
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
AxumJson(serde_json::json!({"error": e.to_string()})),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let responses: Vec<TaskResponse> = tasks
|
|
|
|
|
|
.into_iter()
|
|
|
|
|
|
.map(|t| TaskResponse {
|
|
|
|
|
|
id: t.id,
|
|
|
|
|
|
title: t.title,
|
|
|
|
|
|
description: t.description.unwrap_or_default(),
|
|
|
|
|
|
assignee: t.assignee_id.map(|id| id.to_string()),
|
|
|
|
|
|
reporter: t.reporter_id.map(|id| id.to_string()),
|
|
|
|
|
|
status: t.status,
|
|
|
|
|
|
priority: t.priority,
|
|
|
|
|
|
due_date: t.due_date,
|
|
|
|
|
|
estimated_hours: t.estimated_hours,
|
|
|
|
|
|
actual_hours: t.actual_hours,
|
|
|
|
|
|
tags: t.tags,
|
|
|
|
|
|
parent_task_id: None,
|
|
|
|
|
|
subtasks: vec![],
|
|
|
|
|
|
dependencies: t.dependencies,
|
|
|
|
|
|
attachments: vec![],
|
|
|
|
|
|
comments: vec![],
|
|
|
|
|
|
created_at: t.created_at,
|
|
|
|
|
|
updated_at: t.updated_at,
|
|
|
|
|
|
completed_at: t.completed_at,
|
|
|
|
|
|
progress: t.progress,
|
|
|
|
|
|
})
|
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
|
|
(StatusCode::OK, AxumJson(serde_json::json!(responses)))
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
pub async fn update_task_handler(
|
|
|
|
|
|
AxumState(_engine): AxumState<Arc<TaskEngine>>,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
AxumPath(_id): AxumPath<Uuid>,
|
|
|
|
|
|
AxumJson(_updates): AxumJson<TaskUpdate>,
|
|
|
|
|
|
) -> impl IntoResponse {
|
Add .env.example with comprehensive configuration template
The commit adds a complete example environment configuration file
documenting all available settings for BotServer, including logging,
database, server, drive, LLM, Redis, email, and feature flags.
Also removes hardcoded environment variable usage throughout the
codebase, replacing them with configuration via config.csv or
appropriate defaults. This includes:
- WhatsApp, Teams, Instagram adapter configurations
- Weather API key handling
- Email and directory service configurations
- Console feature conditionally compiles monitoring code
- Improved logging configuration with library suppression
2025-11-28 13:19:03 -03:00
|
|
|
|
let updated = serde_json::json!({
|
|
|
|
|
|
"message": "Task updated",
|
|
|
|
|
|
"task_id": _id
|
|
|
|
|
|
});
|
2025-11-22 22:55:35 -03:00
|
|
|
|
(StatusCode::OK, AxumJson(updated))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
pub async fn get_statistics_handler(
|
|
|
|
|
|
AxumState(_engine): AxumState<Arc<TaskEngine>>,
|
2025-11-22 22:55:35 -03:00
|
|
|
|
AxumQuery(_query): AxumQuery<serde_json::Value>,
|
|
|
|
|
|
) -> impl IntoResponse {
|
|
|
|
|
|
let stats = serde_json::json!({
|
|
|
|
|
|
"todo_count": 0,
|
|
|
|
|
|
"in_progress_count": 0,
|
|
|
|
|
|
"done_count": 0,
|
Add .env.example with comprehensive configuration template
The commit adds a complete example environment configuration file
documenting all available settings for BotServer, including logging,
database, server, drive, LLM, Redis, email, and feature flags.
Also removes hardcoded environment variable usage throughout the
codebase, replacing them with configuration via config.csv or
appropriate defaults. This includes:
- WhatsApp, Teams, Instagram adapter configurations
- Weather API key handling
- Email and directory service configurations
- Console feature conditionally compiles monitoring code
- Improved logging configuration with library suppression
2025-11-28 13:19:03 -03:00
|
|
|
|
"overdue_count": 0,
|
|
|
|
|
|
"total_tasks": 0
|
2025-11-22 22:55:35 -03:00
|
|
|
|
});
|
|
|
|
|
|
(StatusCode::OK, AxumJson(stats))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-26 22:54:22 -03:00
|
|
|
|
pub async fn handle_task_list(
|
2025-11-27 08:34:24 -03:00
|
|
|
|
State(state): State<Arc<AppState>>,
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Query(params): Query<std::collections::HashMap<String, String>>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
) -> Result<Json<Vec<TaskResponse>>, StatusCode> {
|
2025-11-26 22:54:22 -03:00
|
|
|
|
let tasks = if let Some(user_id) = params.get("user_id") {
|
2025-11-27 23:10:43 -03:00
|
|
|
|
let user_uuid = Uuid::parse_str(user_id).unwrap_or_else(|_| Uuid::nil());
|
|
|
|
|
|
match state.task_engine.get_user_tasks(user_uuid).await {
|
2025-11-27 13:53:16 -03:00
|
|
|
|
Ok(tasks) => Ok(tasks),
|
|
|
|
|
|
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
|
|
|
|
}?
|
2025-11-26 22:54:22 -03:00
|
|
|
|
} else if let Some(status_str) = params.get("status") {
|
|
|
|
|
|
let status = match status_str.as_str() {
|
2025-11-27 13:53:16 -03:00
|
|
|
|
"in_progress" => TaskStatus::InProgress,
|
|
|
|
|
|
"review" => TaskStatus::Review,
|
|
|
|
|
|
"done" => TaskStatus::Done,
|
|
|
|
|
|
"blocked" => TaskStatus::Blocked,
|
|
|
|
|
|
"completed" => TaskStatus::Completed,
|
|
|
|
|
|
"cancelled" => TaskStatus::Cancelled,
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
// "todo" and any other status default to Todo
|
|
|
|
|
|
_ => TaskStatus::Todo,
|
2025-11-26 22:54:22 -03:00
|
|
|
|
};
|
2025-12-26 08:59:25 -03:00
|
|
|
|
state
|
|
|
|
|
|
.task_engine
|
|
|
|
|
|
.get_tasks_by_status(status)
|
|
|
|
|
|
.await
|
|
|
|
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
2025-11-26 22:54:22 -03:00
|
|
|
|
} else {
|
2025-12-26 08:59:25 -03:00
|
|
|
|
state
|
|
|
|
|
|
.task_engine
|
|
|
|
|
|
.get_all_tasks()
|
|
|
|
|
|
.await
|
|
|
|
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
2025-11-26 22:54:22 -03:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
|
Ok(Json(
|
|
|
|
|
|
tasks
|
|
|
|
|
|
.into_iter()
|
|
|
|
|
|
.map(|t| t.into())
|
|
|
|
|
|
.collect::<Vec<TaskResponse>>(),
|
|
|
|
|
|
))
|
2025-11-26 22:54:22 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_assign(
|
2025-11-27 08:34:24 -03:00
|
|
|
|
State(state): State<Arc<AppState>>,
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Path(id): Path<Uuid>,
|
|
|
|
|
|
Json(payload): Json<serde_json::Value>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
) -> Result<Json<TaskResponse>, StatusCode> {
|
2025-11-26 22:54:22 -03:00
|
|
|
|
let assignee = payload["assignee"]
|
|
|
|
|
|
.as_str()
|
|
|
|
|
|
.ok_or(StatusCode::BAD_REQUEST)?;
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
match state
|
|
|
|
|
|
.task_engine
|
|
|
|
|
|
.assign_task(id, assignee.to_string())
|
|
|
|
|
|
.await
|
|
|
|
|
|
{
|
|
|
|
|
|
Ok(updated) => Ok(Json(updated.into())),
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_status_update(
|
2025-11-27 08:34:24 -03:00
|
|
|
|
State(state): State<Arc<AppState>>,
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Path(id): Path<Uuid>,
|
|
|
|
|
|
Json(payload): Json<serde_json::Value>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
) -> Result<Json<TaskResponse>, StatusCode> {
|
2025-11-26 22:54:22 -03:00
|
|
|
|
let status_str = payload["status"].as_str().ok_or(StatusCode::BAD_REQUEST)?;
|
|
|
|
|
|
let status = match status_str {
|
2025-11-27 08:34:24 -03:00
|
|
|
|
"todo" => "todo",
|
|
|
|
|
|
"in_progress" => "in_progress",
|
|
|
|
|
|
"review" => "review",
|
|
|
|
|
|
"done" => "completed",
|
|
|
|
|
|
"blocked" => "blocked",
|
|
|
|
|
|
"cancelled" => "cancelled",
|
2025-11-26 22:54:22 -03:00
|
|
|
|
_ => return Err(StatusCode::BAD_REQUEST),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let updates = TaskUpdate {
|
|
|
|
|
|
title: None,
|
|
|
|
|
|
description: None,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
status: Some(status.to_string()),
|
2025-11-26 22:54:22 -03:00
|
|
|
|
priority: None,
|
|
|
|
|
|
assignee: None,
|
|
|
|
|
|
due_date: None,
|
|
|
|
|
|
tags: None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
match state.task_engine.update_task(id, updates).await {
|
2025-11-27 15:19:17 -03:00
|
|
|
|
Ok(updated_task) => Ok(Json(updated_task.into())),
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_priority_set(
|
2025-11-27 08:34:24 -03:00
|
|
|
|
State(state): State<Arc<AppState>>,
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Path(id): Path<Uuid>,
|
|
|
|
|
|
Json(payload): Json<serde_json::Value>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
) -> Result<Json<TaskResponse>, StatusCode> {
|
2025-11-26 22:54:22 -03:00
|
|
|
|
let priority_str = payload["priority"]
|
|
|
|
|
|
.as_str()
|
|
|
|
|
|
.ok_or(StatusCode::BAD_REQUEST)?;
|
|
|
|
|
|
let priority = match priority_str {
|
2025-11-27 08:34:24 -03:00
|
|
|
|
"low" => "low",
|
|
|
|
|
|
"medium" => "medium",
|
|
|
|
|
|
"high" => "high",
|
|
|
|
|
|
"urgent" => "urgent",
|
2025-11-26 22:54:22 -03:00
|
|
|
|
_ => return Err(StatusCode::BAD_REQUEST),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let updates = TaskUpdate {
|
|
|
|
|
|
title: None,
|
|
|
|
|
|
description: None,
|
|
|
|
|
|
status: None,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
priority: Some(priority.to_string()),
|
2025-11-26 22:54:22 -03:00
|
|
|
|
assignee: None,
|
|
|
|
|
|
due_date: None,
|
|
|
|
|
|
tags: None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
match state.task_engine.update_task(id, updates).await {
|
2025-11-27 15:19:17 -03:00
|
|
|
|
Ok(updated_task) => Ok(Json(updated_task.into())),
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
pub async fn handle_task_set_dependencies(
|
|
|
|
|
|
State(state): State<Arc<AppState>>,
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Path(id): Path<Uuid>,
|
|
|
|
|
|
Json(payload): Json<serde_json::Value>,
|
2025-11-27 08:34:24 -03:00
|
|
|
|
) -> Result<Json<TaskResponse>, StatusCode> {
|
2025-11-26 22:54:22 -03:00
|
|
|
|
let deps = payload["dependencies"]
|
|
|
|
|
|
.as_array()
|
|
|
|
|
|
.ok_or(StatusCode::BAD_REQUEST)?
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.filter_map(|v| v.as_str().and_then(|s| Uuid::parse_str(s).ok()))
|
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
match state.task_engine.set_dependencies(id, deps).await {
|
2025-11-27 13:53:16 -03:00
|
|
|
|
Ok(updated) => Ok(Json(updated)),
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 08:34:24 -03:00
|
|
|
|
pub fn configure_task_routes() -> Router<Arc<AppState>> {
|
2025-11-26 22:54:22 -03:00
|
|
|
|
Router::new()
|
2025-11-29 17:27:13 -03:00
|
|
|
|
.route(
|
|
|
|
|
|
ApiUrls::TASKS,
|
|
|
|
|
|
post(handle_task_create).get(handle_task_list_htmx),
|
|
|
|
|
|
)
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
.route("/api/tasks/stats", get(handle_task_stats_htmx))
|
|
|
|
|
|
.route("/api/tasks/stats/json", get(handle_task_stats))
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
.route("/api/tasks/time-saved", get(handle_time_saved))
|
2025-11-29 17:27:13 -03:00
|
|
|
|
.route("/api/tasks/completed", delete(handle_clear_completed))
|
2025-11-29 16:29:28 -03:00
|
|
|
|
.route(
|
2025-12-02 21:09:43 -03:00
|
|
|
|
&ApiUrls::TASK_BY_ID.replace(":id", "{id}"),
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
get(handle_task_get).put(handle_task_update),
|
2025-11-29 16:29:28 -03:00
|
|
|
|
)
|
|
|
|
|
|
.route(
|
2025-12-02 21:09:43 -03:00
|
|
|
|
&ApiUrls::TASK_BY_ID.replace(":id", "{id}"),
|
2025-11-29 17:27:13 -03:00
|
|
|
|
delete(handle_task_delete).patch(handle_task_patch),
|
2025-11-29 16:29:28 -03:00
|
|
|
|
)
|
|
|
|
|
|
.route(
|
2025-12-02 21:09:43 -03:00
|
|
|
|
&ApiUrls::TASK_ASSIGN.replace(":id", "{id}"),
|
2025-11-29 16:29:28 -03:00
|
|
|
|
post(handle_task_assign),
|
|
|
|
|
|
)
|
|
|
|
|
|
.route(
|
2025-12-02 21:09:43 -03:00
|
|
|
|
&ApiUrls::TASK_STATUS.replace(":id", "{id}"),
|
2025-11-29 16:29:28 -03:00
|
|
|
|
put(handle_task_status_update),
|
|
|
|
|
|
)
|
|
|
|
|
|
.route(
|
2025-12-02 21:09:43 -03:00
|
|
|
|
&ApiUrls::TASK_PRIORITY.replace(":id", "{id}"),
|
2025-11-29 16:29:28 -03:00
|
|
|
|
put(handle_task_priority_set),
|
|
|
|
|
|
)
|
2025-11-26 22:54:22 -03:00
|
|
|
|
.route(
|
Add .env.example with comprehensive configuration template
The commit adds a complete example environment configuration file
documenting all available settings for BotServer, including logging,
database, server, drive, LLM, Redis, email, and feature flags.
Also removes hardcoded environment variable usage throughout the
codebase, replacing them with configuration via config.csv or
appropriate defaults. This includes:
- WhatsApp, Teams, Instagram adapter configurations
- Weather API key handling
- Email and directory service configurations
- Console feature conditionally compiles monitoring code
- Improved logging configuration with library suppression
2025-11-28 13:19:03 -03:00
|
|
|
|
"/api/tasks/{id}/dependencies",
|
2025-11-27 08:34:24 -03:00
|
|
|
|
put(handle_task_set_dependencies),
|
2025-11-26 22:54:22 -03:00
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
|
pub fn configure(router: Router<Arc<TaskEngine>>) -> Router<Arc<TaskEngine>> {
|
2025-11-22 22:55:35 -03:00
|
|
|
|
use axum::routing::{get, post, put};
|
|
|
|
|
|
|
|
|
|
|
|
router
|
2025-11-29 16:29:28 -03:00
|
|
|
|
.route(ApiUrls::TASKS, post(handlers::create_task_handler))
|
|
|
|
|
|
.route(ApiUrls::TASKS, get(handlers::get_tasks_handler))
|
|
|
|
|
|
.route(
|
2025-12-02 21:09:43 -03:00
|
|
|
|
&ApiUrls::TASK_BY_ID.replace(":id", "{id}"),
|
2025-11-29 16:29:28 -03:00
|
|
|
|
put(handlers::update_task_handler),
|
|
|
|
|
|
)
|
2025-11-26 22:54:22 -03:00
|
|
|
|
.route(
|
|
|
|
|
|
"/api/tasks/statistics",
|
2025-11-27 23:10:43 -03:00
|
|
|
|
get(handlers::get_statistics_handler),
|
2025-11-26 22:54:22 -03:00
|
|
|
|
)
|
2025-11-22 22:55:35 -03:00
|
|
|
|
}
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_list_htmx(
|
|
|
|
|
|
State(state): State<Arc<AppState>>,
|
|
|
|
|
|
Query(params): Query<std::collections::HashMap<String, String>>,
|
|
|
|
|
|
) -> impl IntoResponse {
|
2025-12-02 21:09:43 -03:00
|
|
|
|
let filter = params
|
|
|
|
|
|
.get("filter")
|
|
|
|
|
|
.cloned()
|
|
|
|
|
|
.unwrap_or_else(|| "all".to_string());
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
|
|
|
|
|
let conn = state.conn.clone();
|
|
|
|
|
|
let filter_clone = filter.clone();
|
|
|
|
|
|
|
|
|
|
|
|
let tasks = tokio::task::spawn_blocking(move || {
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let mut db_conn = conn
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.map_err(|e| format!("DB connection error: {}", e))?;
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let mut query = String::from(
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
"SELECT id, title, status, priority, intent as description, NULL::timestamp as due_date FROM auto_tasks WHERE 1=1",
|
2025-11-30 23:48:08 -03:00
|
|
|
|
);
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
|
|
|
|
|
match filter_clone.as_str() {
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
"complete" | "completed" => query.push_str(" AND status IN ('done', 'completed')"),
|
|
|
|
|
|
"active" => query.push_str(" AND status IN ('running', 'pending', 'in_progress')"),
|
|
|
|
|
|
"awaiting" => query.push_str(" AND status IN ('awaiting_decision', 'awaiting', 'waiting')"),
|
|
|
|
|
|
"paused" => query.push_str(" AND status = 'paused'"),
|
|
|
|
|
|
"blocked" => query.push_str(" AND status IN ('blocked', 'failed', 'error')"),
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
"priority" => query.push_str(" AND priority IN ('high', 'urgent')"),
|
2025-11-29 17:27:13 -03:00
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
query.push_str(" ORDER BY created_at DESC LIMIT 50");
|
|
|
|
|
|
|
|
|
|
|
|
diesel::sql_query(&query)
|
|
|
|
|
|
.load::<TaskRow>(&mut db_conn)
|
|
|
|
|
|
.map_err(|e| format!("Query failed: {}", e))
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
|
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
|
|
log::error!("Task query failed: {}", e);
|
|
|
|
|
|
Err(format!("Task query failed: {}", e))
|
|
|
|
|
|
})
|
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
|
|
let mut html = String::new();
|
|
|
|
|
|
|
|
|
|
|
|
for task in tasks {
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
let is_completed = task.status == "done" || task.status == "completed";
|
|
|
|
|
|
let completed_class = if is_completed { "completed" } else { "" };
|
|
|
|
|
|
|
2025-12-26 08:59:25 -03:00
|
|
|
|
let due_date_html = if let Some(due) = &task.due_date {
|
|
|
|
|
|
format!(
|
|
|
|
|
|
r#"<span class="task-due-date"> {}</span>"#,
|
|
|
|
|
|
due.format("%Y-%m-%d")
|
|
|
|
|
|
)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
String::new()
|
|
|
|
|
|
};
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
let status_class = match task.status.as_str() {
|
|
|
|
|
|
"completed" | "done" => "status-complete",
|
|
|
|
|
|
"running" | "pending" | "in_progress" => "status-running",
|
|
|
|
|
|
"failed" | "error" | "blocked" => "status-error",
|
|
|
|
|
|
"paused" => "status-paused",
|
|
|
|
|
|
"awaiting" | "awaiting_decision" => "status-awaiting",
|
|
|
|
|
|
_ => "status-pending"
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-26 08:59:25 -03:00
|
|
|
|
let _ = write!(
|
|
|
|
|
|
html,
|
2025-11-29 17:27:13 -03:00
|
|
|
|
r#"
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
<div class="task-card {completed_class} {status_class}" data-task-id="{}" onclick="selectTask('{}')">
|
|
|
|
|
|
<div class="task-card-header">
|
|
|
|
|
|
<span class="task-card-title">{}</span>
|
|
|
|
|
|
<span class="task-card-status {}">{}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="task-card-body">
|
|
|
|
|
|
<div class="task-card-priority">
|
|
|
|
|
|
<span class="priority-badge priority-{}">{}</span>
|
2025-11-29 17:27:13 -03:00
|
|
|
|
</div>
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
{due_date_html}
|
2025-11-29 17:27:13 -03:00
|
|
|
|
</div>
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
<div class="task-card-footer">
|
|
|
|
|
|
<button class="task-action-btn" data-action="priority" data-task-id="{}" onclick="event.stopPropagation()">
|
2025-11-29 17:27:13 -03:00
|
|
|
|
⭐
|
|
|
|
|
|
</button>
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
<button class="task-action-btn" data-action="delete" data-task-id="{}" onclick="event.stopPropagation()">
|
|
|
|
|
|
🗑️
|
2025-11-29 17:27:13 -03:00
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
"#,
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
task.id,
|
|
|
|
|
|
task.id,
|
|
|
|
|
|
task.title,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
status_class,
|
|
|
|
|
|
task.status,
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
task.priority,
|
|
|
|
|
|
task.priority,
|
|
|
|
|
|
task.id,
|
|
|
|
|
|
task.id
|
2025-12-26 08:59:25 -03:00
|
|
|
|
);
|
2025-11-29 17:27:13 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if html.is_empty() {
|
|
|
|
|
|
html = format!(
|
|
|
|
|
|
r#"
|
|
|
|
|
|
<div class="empty-state">
|
|
|
|
|
|
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
|
|
|
|
|
|
<polyline points="9 11 12 14 22 4"></polyline>
|
|
|
|
|
|
<path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
<h3>No {} tasks</h3>
|
|
|
|
|
|
<p>{}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
"#,
|
|
|
|
|
|
filter,
|
|
|
|
|
|
if filter == "all" {
|
|
|
|
|
|
"Create your first task to get started"
|
|
|
|
|
|
} else {
|
|
|
|
|
|
"Switch to another view or add new tasks"
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
axum::response::Html(html)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
pub async fn handle_task_stats_htmx(State(state): State<Arc<AppState>>) -> impl IntoResponse {
|
|
|
|
|
|
let conn = state.conn.clone();
|
|
|
|
|
|
|
|
|
|
|
|
let stats = tokio::task::spawn_blocking(move || {
|
|
|
|
|
|
let mut db_conn = conn
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.map_err(|e| format!("DB connection error: {}", e))?;
|
|
|
|
|
|
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
let total: i64 = diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks")
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let active: i64 =
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('running', 'pending', 'in_progress')")
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let completed: i64 =
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('done', 'completed')")
|
|
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let awaiting: i64 =
|
|
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('awaiting_decision', 'awaiting', 'waiting')")
|
|
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let paused: i64 =
|
|
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status = 'paused'")
|
|
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let blocked: i64 =
|
|
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('blocked', 'failed', 'error')")
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let priority: i64 =
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE priority IN ('high', 'urgent')")
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
let time_saved = format!("{}h", completed * 2);
|
|
|
|
|
|
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
Ok::<_, String>(TaskStats {
|
|
|
|
|
|
total: total as usize,
|
|
|
|
|
|
active: active as usize,
|
|
|
|
|
|
completed: completed as usize,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
awaiting: awaiting as usize,
|
|
|
|
|
|
paused: paused as usize,
|
|
|
|
|
|
blocked: blocked as usize,
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
priority: priority as usize,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
time_saved,
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
|
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
|
|
log::error!("Stats query failed: {}", e);
|
|
|
|
|
|
Err(format!("Stats query failed: {}", e))
|
|
|
|
|
|
})
|
|
|
|
|
|
.unwrap_or(TaskStats {
|
|
|
|
|
|
total: 0,
|
|
|
|
|
|
active: 0,
|
|
|
|
|
|
completed: 0,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
awaiting: 0,
|
|
|
|
|
|
paused: 0,
|
|
|
|
|
|
blocked: 0,
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
priority: 0,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
time_saved: "0h".to_string(),
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
let html = format!(
|
|
|
|
|
|
"{} tasks
|
|
|
|
|
|
<script>
|
|
|
|
|
|
document.getElementById('count-all').textContent = '{}';
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
document.getElementById('count-complete').textContent = '{}';
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
document.getElementById('count-active').textContent = '{}';
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
document.getElementById('count-awaiting').textContent = '{}';
|
|
|
|
|
|
document.getElementById('count-paused').textContent = '{}';
|
|
|
|
|
|
document.getElementById('count-blocked').textContent = '{}';
|
|
|
|
|
|
document.getElementById('time-saved-value').textContent = '{}';
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
</script>",
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
stats.total, stats.total, stats.completed, stats.active, stats.awaiting, stats.paused, stats.blocked, stats.time_saved
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
axum::response::Html(html)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-29 17:27:13 -03:00
|
|
|
|
pub async fn handle_task_stats(State(state): State<Arc<AppState>>) -> Json<TaskStats> {
|
|
|
|
|
|
let conn = state.conn.clone();
|
|
|
|
|
|
|
|
|
|
|
|
let stats = tokio::task::spawn_blocking(move || {
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let mut db_conn = conn
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.map_err(|e| format!("DB connection error: {}", e))?;
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
let total: i64 = diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks")
|
2025-11-29 17:27:13 -03:00
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let active: i64 =
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('running', 'pending', 'in_progress')")
|
2025-11-30 23:48:08 -03:00
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let completed: i64 =
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('done', 'completed')")
|
|
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let awaiting: i64 =
|
|
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('awaiting_decision', 'awaiting', 'waiting')")
|
|
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let paused: i64 =
|
|
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status = 'paused'")
|
|
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
let blocked: i64 =
|
|
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('blocked', 'failed', 'error')")
|
2025-11-30 23:48:08 -03:00
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let priority: i64 =
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE priority IN ('high', 'urgent')")
|
2025-11-30 23:48:08 -03:00
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
let time_saved = format!("{}h", completed * 2);
|
|
|
|
|
|
|
2025-11-29 17:27:13 -03:00
|
|
|
|
Ok::<_, String>(TaskStats {
|
|
|
|
|
|
total: total as usize,
|
|
|
|
|
|
active: active as usize,
|
|
|
|
|
|
completed: completed as usize,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
awaiting: awaiting as usize,
|
|
|
|
|
|
paused: paused as usize,
|
|
|
|
|
|
blocked: blocked as usize,
|
2025-11-29 17:27:13 -03:00
|
|
|
|
priority: priority as usize,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
time_saved,
|
2025-11-29 17:27:13 -03:00
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
|
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
|
|
log::error!("Stats query failed: {}", e);
|
|
|
|
|
|
Err(format!("Stats query failed: {}", e))
|
|
|
|
|
|
})
|
|
|
|
|
|
.unwrap_or(TaskStats {
|
|
|
|
|
|
total: 0,
|
|
|
|
|
|
active: 0,
|
|
|
|
|
|
completed: 0,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
awaiting: 0,
|
|
|
|
|
|
paused: 0,
|
|
|
|
|
|
blocked: 0,
|
2025-11-29 17:27:13 -03:00
|
|
|
|
priority: 0,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
time_saved: "0h".to_string(),
|
2025-11-29 17:27:13 -03:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
Json(stats)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
pub async fn handle_time_saved(State(state): State<Arc<AppState>>) -> impl IntoResponse {
|
|
|
|
|
|
let conn = state.conn.clone();
|
|
|
|
|
|
|
|
|
|
|
|
let time_saved = tokio::task::spawn_blocking(move || {
|
|
|
|
|
|
let mut db_conn = match conn.get() {
|
|
|
|
|
|
Ok(c) => c,
|
|
|
|
|
|
Err(_) => return "0h".to_string(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let completed: i64 =
|
|
|
|
|
|
diesel::sql_query("SELECT COUNT(*) as count FROM auto_tasks WHERE status IN ('done', 'completed')")
|
|
|
|
|
|
.get_result::<CountResult>(&mut db_conn)
|
|
|
|
|
|
.map(|r| r.count)
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
format!("{}h", completed * 2)
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
|
|
|
|
|
.unwrap_or_else(|_| "0h".to_string());
|
|
|
|
|
|
|
|
|
|
|
|
axum::response::Html(format!(
|
|
|
|
|
|
r#"<span class="time-label">Active Time Saved:</span>
|
|
|
|
|
|
<span class="time-value" id="time-saved-value">{}</span>"#,
|
|
|
|
|
|
time_saved
|
|
|
|
|
|
))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-29 17:27:13 -03:00
|
|
|
|
pub async fn handle_clear_completed(State(state): State<Arc<AppState>>) -> impl IntoResponse {
|
|
|
|
|
|
let conn = state.conn.clone();
|
|
|
|
|
|
|
|
|
|
|
|
tokio::task::spawn_blocking(move || {
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let mut db_conn = conn
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.map_err(|e| format!("DB connection error: {}", e))?;
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
diesel::sql_query("DELETE FROM auto_tasks WHERE status IN ('done', 'completed')")
|
2025-11-29 17:27:13 -03:00
|
|
|
|
.execute(&mut db_conn)
|
|
|
|
|
|
.map_err(|e| format!("Delete failed: {}", e))?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok::<_, String>(())
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
|
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
|
|
log::error!("Clear completed failed: {}", e);
|
|
|
|
|
|
Err(format!("Clear completed failed: {}", e))
|
|
|
|
|
|
})
|
|
|
|
|
|
.ok();
|
|
|
|
|
|
|
|
|
|
|
|
log::info!("Cleared completed tasks");
|
|
|
|
|
|
|
|
|
|
|
|
handle_task_list_htmx(State(state), Query(std::collections::HashMap::new())).await
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn handle_task_patch(
|
|
|
|
|
|
State(state): State<Arc<AppState>>,
|
|
|
|
|
|
Path(id): Path<String>,
|
|
|
|
|
|
Json(update): Json<TaskPatch>,
|
|
|
|
|
|
) -> Result<Json<ApiResponse<()>>, (StatusCode, String)> {
|
|
|
|
|
|
log::info!("Updating task {} with {:?}", id, update);
|
|
|
|
|
|
|
|
|
|
|
|
let conn = state.conn.clone();
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let task_id = id
|
|
|
|
|
|
.parse::<Uuid>()
|
|
|
|
|
|
.map_err(|e| (StatusCode::BAD_REQUEST, format!("Invalid task ID: {}", e)))?;
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
|
|
|
|
|
tokio::task::spawn_blocking(move || {
|
2025-11-30 23:48:08 -03:00
|
|
|
|
let mut db_conn = conn
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.map_err(|e| format!("DB connection error: {}", e))?;
|
2025-11-29 17:27:13 -03:00
|
|
|
|
|
|
|
|
|
|
if let Some(completed) = update.completed {
|
|
|
|
|
|
diesel::sql_query("UPDATE tasks SET completed = $1 WHERE id = $2")
|
|
|
|
|
|
.bind::<diesel::sql_types::Bool, _>(completed)
|
|
|
|
|
|
.bind::<diesel::sql_types::Uuid, _>(task_id)
|
|
|
|
|
|
.execute(&mut db_conn)
|
|
|
|
|
|
.map_err(|e| format!("Update failed: {}", e))?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(priority) = update.priority {
|
|
|
|
|
|
diesel::sql_query("UPDATE tasks SET priority = $1 WHERE id = $2")
|
|
|
|
|
|
.bind::<diesel::sql_types::Bool, _>(priority)
|
|
|
|
|
|
.bind::<diesel::sql_types::Uuid, _>(task_id)
|
|
|
|
|
|
.execute(&mut db_conn)
|
|
|
|
|
|
.map_err(|e| format!("Update failed: {}", e))?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(text) = update.text {
|
|
|
|
|
|
diesel::sql_query("UPDATE tasks SET title = $1 WHERE id = $2")
|
|
|
|
|
|
.bind::<diesel::sql_types::Text, _>(text)
|
|
|
|
|
|
.bind::<diesel::sql_types::Uuid, _>(task_id)
|
|
|
|
|
|
.execute(&mut db_conn)
|
|
|
|
|
|
.map_err(|e| format!("Update failed: {}", e))?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok::<_, String>(())
|
|
|
|
|
|
})
|
|
|
|
|
|
.await
|
2025-11-30 23:48:08 -03:00
|
|
|
|
.map_err(|e| {
|
|
|
|
|
|
(
|
|
|
|
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
format!("Task join error: {}", e),
|
|
|
|
|
|
)
|
|
|
|
|
|
})?
|
2025-11-29 17:27:13 -03:00
|
|
|
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e))?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(Json(ApiResponse {
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: Some(()),
|
|
|
|
|
|
message: Some("Task updated".to_string()),
|
|
|
|
|
|
}))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct TaskStats {
|
|
|
|
|
|
pub total: usize,
|
|
|
|
|
|
pub active: usize,
|
|
|
|
|
|
pub completed: usize,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
pub awaiting: usize,
|
|
|
|
|
|
pub paused: usize,
|
|
|
|
|
|
pub blocked: usize,
|
2025-11-29 17:27:13 -03:00
|
|
|
|
pub priority: usize,
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
|
pub time_saved: String,
|
2025-11-29 17:27:13 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct TaskPatch {
|
|
|
|
|
|
pub completed: Option<bool>,
|
|
|
|
|
|
pub priority: Option<bool>,
|
|
|
|
|
|
pub text: Option<String>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
|
|
pub struct ApiResponse<T> {
|
|
|
|
|
|
pub success: bool,
|
|
|
|
|
|
pub data: Option<T>,
|
|
|
|
|
|
pub message: Option<String>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, QueryableByName)]
|
|
|
|
|
|
struct TaskRow {
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Uuid)]
|
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Text)]
|
|
|
|
|
|
pub title: String,
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Text)]
|
|
|
|
|
|
pub status: String,
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Text)]
|
|
|
|
|
|
pub priority: String,
|
2025-11-29 17:27:13 -03:00
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Text>)]
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
|
pub description: Option<String>,
|
2025-11-29 17:27:13 -03:00
|
|
|
|
#[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>)]
|
|
|
|
|
|
pub due_date: Option<chrono::DateTime<chrono::Utc>>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, QueryableByName)]
|
|
|
|
|
|
struct CountResult {
|
|
|
|
|
|
#[diesel(sql_type = diesel::sql_types::BigInt)]
|
|
|
|
|
|
pub count: i64,
|
|
|
|
|
|
}
|