sage-cli 0.13.57

Command-line interface for Sage Agent
//! Executor creation logic

use sage_core::agent::UnifiedExecutor;
use sage_core::agent::{ExecutionMode, ExecutionOptions};
use sage_core::error::SageResult;
use sage_core::mcp::{clear_active_mcp_registry, set_active_mcp_registry};
use sage_core::output::{OutputMode, UiEventOutput};
use sage_core::ui::traits::UiContext;
use std::sync::Arc;

/// Create executor with unified configuration path
pub async fn create_executor(
    ui_context: Option<UiContext>,
    config_file: &str,
    working_dir: Option<std::path::PathBuf>,
    max_steps: Option<u32>,
) -> SageResult<UnifiedExecutor> {
    let config = if std::path::Path::new(config_file).exists() {
        sage_core::config::load_config_from_file(config_file)?
    } else {
        sage_core::config::load_config()?
    };

    let resolved_working_dir = working_dir
        .or_else(|| config.working_directory.clone())
        .unwrap_or_else(|| {
            std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."))
        });

    let mut options = ExecutionOptions::default()
        .with_mode(ExecutionMode::interactive())
        .with_working_directory(&resolved_working_dir);

    if let Some(steps) = max_steps {
        options = options.with_step_limit(steps);
    }

    let mut executor = UnifiedExecutor::with_options(config.clone(), options)?;

    if let Some(ctx) = ui_context {
        executor.set_ui_context(ctx.clone());
        executor.set_output_strategy(Arc::new(UiEventOutput::new(ctx)));
    } else {
        executor.set_output_mode(OutputMode::Rnk);
    }

    // Register default tools
    let mut all_tools = sage_tools::get_default_tools_with_context(
        resolved_working_dir.clone(),
        executor.skill_registry(),
    );

    // Load MCP tools if MCP is enabled
    if config.mcp.enabled {
        match crate::commands::unified::build_mcp_registry_from_config(&config).await {
            Ok(mcp_registry) => {
                let mcp_registry = Arc::new(mcp_registry);
                set_active_mcp_registry(Arc::clone(&mcp_registry));
                let mcp_tools = mcp_registry.as_tools().await;
                if !mcp_tools.is_empty() {
                    all_tools.extend(mcp_tools);
                }
            }
            Err(e) => {
                clear_active_mcp_registry();
                tracing::error!("Failed to build MCP registry: {}", e);
            }
        }
    } else {
        clear_active_mcp_registry();
    }

    executor.register_tools(all_tools);
    if let Err(e) = executor.init_subagent_support() {
        tracing::warn!("Failed to initialize subagent support: {}", e);
    }

    // Set up JSONL storage for session management
    let jsonl_storage = sage_core::session::JsonlSessionStorage::default_path()?;
    executor.set_jsonl_storage(std::sync::Arc::new(jsonl_storage));

    // Enable JSONL session recording
    if let Err(e) = executor.enable_session_recording().await {
        tracing::warn!("Failed to enable session recording: {}", e);
    }

    Ok(executor)
}