vtcode 0.98.7

A Rust-based terminal coding agent with modular architecture supporting multiple LLM providers
use std::time::Duration;

use anyhow::{Result, bail};
use vtcode_core::cli::args::BackgroundSubagentArgs;
use vtcode_core::subagents::{SpawnAgentRequest, SubagentController, SubagentControllerConfig};
use vtcode_core::tools::exec_session::ExecSessionManager;
use vtcode_core::tools::registry::PtySessionManager;

use crate::startup::StartupContext;

pub(crate) async fn handle_background_subagent_command(
    startup: &StartupContext,
    args: BackgroundSubagentArgs,
) -> Result<()> {
    if args.prompt.trim().is_empty() {
        bail!("background subagent prompt cannot be empty");
    }

    let workspace_root = startup.agent_config.workspace.clone();
    let mut vt_cfg = startup.config.clone();
    vt_cfg.subagents.background.auto_restore = false;

    let pty_sessions = PtySessionManager::new(workspace_root.clone(), vt_cfg.pty.clone());
    let exec_sessions = ExecSessionManager::new(workspace_root.clone(), pty_sessions.clone());
    let controller = SubagentController::new(SubagentControllerConfig {
        workspace_root,
        parent_session_id: args.parent_session_id,
        parent_model: startup.agent_config.model.clone(),
        parent_provider: startup.agent_config.provider.clone(),
        parent_reasoning_effort: startup.agent_config.reasoning_effort,
        api_key: startup.agent_config.api_key.clone(),
        vt_cfg,
        openai_chatgpt_auth: startup.agent_config.openai_chatgpt_auth.clone(),
        depth: 0,
        exec_sessions,
        pty_manager: pty_sessions.manager().clone(),
    })
    .await?;

    controller
        .set_turn_delegation_hints_from_input("delegate this task to a background subagent")
        .await;
    controller
        .set_parent_session_id(args.session_id.clone())
        .await;

    let spawned = controller
        .spawn(SpawnAgentRequest {
            agent_type: Some(args.agent_name.clone()),
            message: Some(args.prompt.clone()),
            background: true,
            max_turns: args.max_turns,
            model: args.model_override.clone(),
            reasoning_effort: args.reasoning_override.clone(),
            ..SpawnAgentRequest::default()
        })
        .await?;

    let status = controller
        .wait(std::slice::from_ref(&spawned.id), Some(300_000))
        .await?;
    if let Some(status) = status {
        if let Some(summary) = status.summary.as_deref() {
            println!("background-subagent-summary: {}", summary.trim());
        }
        if let Some(error) = status.error.as_deref() {
            eprintln!("background-subagent-error: {}", error.trim());
        }
        if !status.status.is_terminal()
            || matches!(
                status.status,
                vtcode_core::subagents::SubagentStatus::Completed
            )
        {
            println!(
                "background-subagent-ready: {} {}",
                status.agent_name, status.session_id
            );
        } else {
            bail!(
                "background subagent '{}' exited with status {}",
                status.agent_name,
                status.status.as_str()
            );
        }
    } else {
        println!(
            "background-subagent-ready: {} {}",
            args.agent_name, args.session_id
        );
    }

    loop {
        tokio::time::sleep(Duration::from_secs(3600)).await;
    }
}