use std::path::PathBuf;
use crate::execution_graph::{ExecutionGraph, RunTelemetry};
use crate::validation_loop::ValidationConfig;
pub(super) const EXTERNAL_CONTENT_TOOLS: &[&str] = &[
"fetch_url",
"web_fetch",
"web_search",
"context_recall",
"semantic_search",
];
pub(super) const DEFAULT_LOOP_DETECTION_WINDOW: usize = 5;
pub(super) const DEFAULT_MAX_ITERATIONS: u32 = 100;
#[derive(Debug, Clone)]
pub struct LoopDetectionConfig {
pub window_size: usize,
pub enabled: bool,
}
impl Default for LoopDetectionConfig {
fn default() -> Self {
Self {
window_size: DEFAULT_LOOP_DETECTION_WINDOW,
enabled: true,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TaskAgentStatus {
Idle,
Working(String),
WaitingForLock(String),
Paused(String),
Replanning(String),
Completed(String),
Failed(String),
}
impl std::fmt::Display for TaskAgentStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TaskAgentStatus::Idle => write!(f, "Idle"),
TaskAgentStatus::Working(desc) => write!(f, "Working: {}", desc),
TaskAgentStatus::WaitingForLock(path) => write!(f, "Waiting for lock: {}", path),
TaskAgentStatus::Paused(reason) => write!(f, "Paused: {}", reason),
TaskAgentStatus::Replanning(reason) => write!(f, "Replanning: {}", reason),
TaskAgentStatus::Completed(summary) => write!(f, "Completed: {}", summary),
TaskAgentStatus::Failed(error) => write!(f, "Failed: {}", error),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum FailureCategory {
IterationLimitExceeded,
TokenBudgetExceeded,
CostBudgetExceeded,
WallClockTimeout,
LoopDetected,
MaxReplanAttemptsExceeded,
FileScopeViolation,
ValidationFailed,
ToolExecutionError,
Unknown,
PlanBudgetExceeded,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TaskAgentResult {
pub agent_id: String,
pub task_id: String,
pub success: bool,
pub summary: String,
pub iterations: u32,
pub replan_count: u32,
pub budget_exhausted: bool,
pub partial_output: Option<String>,
pub total_tokens_used: u64,
pub total_cost_usd: f64,
pub timed_out: bool,
pub failure_category: Option<FailureCategory>,
pub execution_graph: ExecutionGraph,
pub telemetry: RunTelemetry,
pub pre_execution_plan: Option<brainwires_core::SerializablePlan>,
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct TaskAgentConfig {
pub max_iterations: u32,
pub system_prompt: Option<String>,
pub temperature: f32,
pub max_tokens: u32,
pub validation_config: Option<ValidationConfig>,
pub loop_detection: Option<LoopDetectionConfig>,
pub goal_revalidation_interval: Option<u32>,
pub max_replan_attempts: u32,
pub max_total_tokens: Option<u64>,
pub max_cost_usd: Option<f64>,
pub timeout_secs: Option<u64>,
pub allowed_files: Option<Vec<PathBuf>>,
pub plan_budget: Option<brainwires_core::PlanBudget>,
pub context_budget_tokens: Option<u64>,
#[cfg(feature = "telemetry")]
pub analytics_collector: Option<std::sync::Arc<brainwires_telemetry::AnalyticsCollector>>,
#[cfg(feature = "telemetry")]
pub billing_hook: Option<crate::task_agent::BillingHookRef>,
}
impl Default for TaskAgentConfig {
fn default() -> Self {
Self {
max_iterations: DEFAULT_MAX_ITERATIONS,
system_prompt: None,
temperature: 0.7,
max_tokens: 4096,
validation_config: Some(ValidationConfig::default()),
loop_detection: Some(LoopDetectionConfig::default()),
goal_revalidation_interval: Some(10),
max_replan_attempts: 3,
max_total_tokens: None,
max_cost_usd: None,
timeout_secs: None,
allowed_files: None,
plan_budget: None,
context_budget_tokens: None,
#[cfg(feature = "telemetry")]
analytics_collector: None,
#[cfg(feature = "telemetry")]
billing_hook: None,
}
}
}