use std::str::FromStr;
use std::time::{SystemTime, UNIX_EPOCH};
use anyhow::{Context, Result, anyhow, bail};
use vtcode_core::config::VTCodeConfig;
use vtcode_core::config::models::ModelId;
use vtcode_core::config::types::AgentConfig as CoreAgentConfig;
use vtcode_core::core::agent::runner::{AgentRunner, RunnerSettings};
use vtcode_core::core::agent::task::{ContextItem, Task};
use vtcode_core::core::agent::types::AgentType;
use vtcode_core::utils::colors::style;
use crate::startup::require_full_auto_workspace_trust;
const AUTO_SESSION_PREFIX: &str = "auto-task";
const AUTO_TASK_ID: &str = "auto-task";
const AUTO_TASK_TITLE: &str = "Autonomous Task";
pub async fn handle_auto_task_command(
config: &CoreAgentConfig,
vt_cfg: &VTCodeConfig,
prompt: &str,
) -> Result<()> {
let trimmed = prompt.trim();
if trimmed.is_empty() {
bail!("Automation prompt is empty. Provide instructions after --auto/--full-auto.");
}
require_full_auto_workspace_trust(&config.workspace, "autonomous runs", "--auto/--full-auto")
.await?;
let automation_cfg = &vt_cfg.automation.full_auto;
if !automation_cfg.enabled {
bail!(
"Automation is disabled in configuration. Enable [automation.full_auto] to continue."
);
}
if config
.provider
.eq_ignore_ascii_case(crate::codex_app_server::CODEX_PROVIDER)
{
let completed = crate::codex_app_server::run_codex_noninteractive(
config,
Some(vt_cfg),
crate::codex_app_server::CodexNonInteractiveRun {
prompt: trimmed.to_string(),
read_only: false,
plan_mode: false,
skip_confirmations: true,
ephemeral: true,
resume_thread_id: None,
seed_messages: Vec::new(),
review_target: None,
},
)
.await?;
if !completed.output.trim().is_empty() {
println!("{}", completed.output.trim());
}
return Ok(());
}
let model_id = ModelId::from_str(&config.model).with_context(|| {
format!(
"Model '{}' is not recognized for autonomous execution. Update vtcode.toml to a \
supported identifier.",
config.model
)
})?;
let session_id = format!(
"{AUTO_SESSION_PREFIX}-{}",
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|err| anyhow!("Failed to derive session identifier timestamp: {}", err))?
.as_secs()
);
let mut runner = AgentRunner::new_with_openai_auth(
AgentType::Single,
model_id,
config.api_key.clone(),
config.workspace.clone(),
session_id,
RunnerSettings {
reasoning_effort: Some(config.reasoning_effort),
verbosity: None,
},
None,
config.openai_chatgpt_auth.clone(),
)
.await?;
runner.enable_full_auto(&automation_cfg.allowed_tools).await;
let task = Task {
id: AUTO_TASK_ID.to_string(),
title: AUTO_TASK_TITLE.to_string(),
description: trimmed.to_string(),
instructions: None,
};
let max_retries = vt_cfg.agent.max_task_retries;
let result = runner
.execute_task_with_retry(&task, &[] as &[ContextItem], max_retries)
.await
.context("Failed to execute autonomous task after retries")?;
if !result.summary.trim().is_empty() {
println!(
"{} {}",
style("[SUMMARY]").green().bold(),
result.summary.trim()
);
}
if !result.modified_files.is_empty() {
println!(
"{} {}",
style("[FILES]").cyan().bold(),
result.modified_files.join(", ")
);
}
if !result.executed_commands.is_empty() {
println!(
"{} {}",
style("[COMMANDS]").cyan().bold(),
result.executed_commands.join(", ")
);
}
if !result.warnings.is_empty() {
for warning in result.warnings {
println!("{} {}", style("[WARNING]").red().bold(), warning);
}
}
Ok(())
}