//! Agent task service — managing task/sub-agent execution lifecycle. //! //! A task (`agent_task` record) can be: //! - A **root task**: initiated by a user or system event. //! The parent/Supervisor agent spawns sub-tasks and coordinates their results. //! - A **sub-task**: a unit of work executed by a sub-agent. //! //! Execution flow: //! 1. Create task record (status = pending) //! 2. Notify listeners (WebSocket: task_started) //! 3. Spawn execution (tokio::spawn or via room queue) //! 4. Update progress (status = running, progress = "step 2/5: ...") //! 5. On completion: update output + status = done / error + status = failed //! 6. Notify listeners (WebSocket: task_done) //! 7. If root task: notify parent/Supervisor to aggregate results //! //! This module is intentionally kept simple and synchronous with the DB. //! Long-running execution is delegated to the caller (tokio::spawn). pub mod events; pub mod lifecycle; pub mod store; pub mod tree; use db::database::AppDatabase; pub use events::{NoOpPublisher, TaskEvent, TaskEventPublisher, TaskEvents}; pub use lifecycle::TaskLifecycle; /// Service for managing agent tasks (root tasks and sub-tasks). #[derive(Clone)] pub struct TaskService { db: AppDatabase, events: TaskEvents, } impl TaskService { pub fn new(db: AppDatabase) -> Self { Self { db, events: TaskEvents::noop(), } } pub fn with_events(db: AppDatabase, events: TaskEvents) -> Self { Self { db, events } } pub(crate) fn db(&self) -> &AppDatabase { &self.db } pub(crate) fn events(&self) -> &TaskEvents { &self.events } } /// Builder for TaskService so that the events publisher can be set independently /// of the database connection. #[derive(Clone, Default)] pub struct TaskServiceBuilder { events: Option, } impl TaskServiceBuilder { pub fn with_events(mut self, events: TaskEvents) -> Self { self.events = Some(events); self } pub async fn build(self, db: AppDatabase) -> TaskService { TaskService { db, events: self.events.unwrap_or_else(TaskEvents::noop), } } }