gitdataai/libs/models/agent_task/mod.rs
ZhenYi a09ff66191 refactor(room): remove NATS, use Redis pub/sub for message queue
- Remove async-nats from Cargo.toml dependencies
- Rename nats_publish_failed metric → redis_publish_failed
- Update queue lib doc comment: Redis Streams + Redis Pub/Sub
- Add Paused/Cancelled task statuses to agent_task model
- Add issue_id and retry_count fields to agent_task
- Switch tool executor Mutex from std::sync → tokio::sync (async context)
- Add timeout/rate-limited/retryable/tool-not-found error variants
2026-04-16 17:24:04 +08:00

175 lines
5.0 KiB
Rust

//! Agent task model — sub-agents and sub-tasks as a unified concept.
//!
//! An `agent_task` represents either:
//! - A **root task** (parent_id = NULL): initiated by a user or system event.
//! The parent agent (Supervisor) spawns sub-tasks and coordinates their results.
//! - A **sub-task** (parent_id = set): a unit of work executed by a sub-agent.
//!
//! Status lifecycle: `pending` → `running` → `done` | `failed`
//!
//! Sub-agents are represented as `agent_task` records with a parent reference,
//! allowing hierarchical task trees and result aggregation.
use crate::{DateTimeUtc, IssueId, ProjectId, UserId};
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
/// Agent task type — the kind of agent that executes this task.
#[derive(
Clone, Debug, PartialEq, Eq, EnumIter, Serialize, Deserialize, sea_orm::DeriveActiveEnum,
)]
#[sea_orm(rs_type = "String", db_type = "String(StringLen::None)")]
pub enum AgentType {
#[sea_orm(string_value = "React")]
React,
#[sea_orm(string_value = "Chat")]
Chat,
}
impl Default for AgentType {
fn default() -> Self {
AgentType::React
}
}
impl std::fmt::Display for AgentType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AgentType::React => write!(f, "React"),
AgentType::Chat => write!(f, "Chat"),
}
}
}
/// Task status lifecycle.
#[derive(
Clone, Debug, PartialEq, Eq, EnumIter, Serialize, Deserialize, sea_orm::DeriveActiveEnum,
)]
#[sea_orm(rs_type = "String", db_type = "String(StringLen::None)")]
pub enum TaskStatus {
#[sea_orm(string_value = "Pending")]
Pending,
#[sea_orm(string_value = "Running")]
Running,
#[sea_orm(string_value = "Paused")]
Paused,
#[sea_orm(string_value = "Done")]
Done,
#[sea_orm(string_value = "Failed")]
Failed,
#[sea_orm(string_value = "Cancelled")]
Cancelled,
}
impl Default for TaskStatus {
fn default() -> Self {
TaskStatus::Pending
}
}
impl std::fmt::Display for TaskStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TaskStatus::Pending => write!(f, "Pending"),
TaskStatus::Running => write!(f, "Running"),
TaskStatus::Paused => write!(f, "Paused"),
TaskStatus::Done => write!(f, "Done"),
TaskStatus::Failed => write!(f, "Failed"),
TaskStatus::Cancelled => write!(f, "Cancelled"),
}
}
}
/// Agent task record — represents both root tasks and sub-tasks.
#[derive(Clone, Debug, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "agent_task")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i64,
/// Project this task belongs to.
pub project_uuid: ProjectId,
/// Parent task (NULL for root tasks, set for sub-tasks).
#[sea_orm(nullable)]
pub parent_id: Option<i64>,
/// Issue this task is bound to (optional).
#[sea_orm(nullable)]
pub issue_id: Option<IssueId>,
/// Agent type that executes this task.
#[sea_orm(column_type = "String(StringLen::None)", default = "React")]
pub agent_type: AgentType,
/// Current task status.
#[sea_orm(column_type = "String(StringLen::None)", default = "Pending")]
pub status: TaskStatus,
/// Human-readable task title / goal description.
#[sea_orm(nullable)]
pub title: Option<String>,
/// Task input — the prompt or goal text.
pub input: String,
/// Task output — populated when status = done.
#[sea_orm(nullable)]
pub output: Option<String>,
/// Error message — populated when status = failed.
#[sea_orm(nullable)]
pub error: Option<String>,
/// User who initiated this task.
#[sea_orm(nullable)]
pub created_by: Option<UserId>,
pub created_at: DateTimeUtc,
pub updated_at: DateTimeUtc,
/// When execution started (status → running).
#[sea_orm(nullable)]
pub started_at: Option<DateTimeUtc>,
/// When execution completed (status → done | failed).
#[sea_orm(nullable)]
pub done_at: Option<DateTimeUtc>,
/// Current progress description (e.g., "step 2/5: analyzing code").
#[sea_orm(nullable)]
pub progress: Option<String>,
/// Number of times this task has been retried.
#[sea_orm(nullable)]
pub retry_count: Option<i32>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(belongs_to = "Entity", from = "Column::ParentId", to = "Column::Id")]
ParentTask,
}
impl ActiveModelBehavior for ActiveModel {}
impl Model {
pub fn is_root_task(&self) -> bool {
self.parent_id.is_none()
}
pub fn is_done(&self) -> bool {
matches!(
self.status,
TaskStatus::Done | TaskStatus::Failed | TaskStatus::Cancelled
)
}
pub fn is_running(&self) -> bool {
matches!(
self.status,
TaskStatus::Running | TaskStatus::Pending | TaskStatus::Paused
)
}
}