use crate::agent::{Agent, find_agent};
use crate::exec::cli::RunArgs;
use crate::hub::{HubEvent, get_hub};
use crate::run::{RunRedoCtx, RunTopAgentParams, run_agent};
use crate::runtime::Runtime;
use crate::support::jsons::into_values;
use crate::support::{editor, text};
use crate::types::{FileInfo, RunAgentResponse};
use crate::{Error, Result, term};
use simple_fs::{SEventKind, SPath, list_files, watch};
use tracing::info;
pub async fn exec_run(run_args: RunArgs, runtime: Runtime) -> Result<(RunRedoCtx, bool)> {
tokio::task::yield_now().await;
let (redo_ctx, redo_requested) = exec_run_first(run_args, runtime).await?;
if redo_ctx.run_options().base_run_options().watch() {
exec_run_watch(redo_ctx.clone());
}
Ok((redo_ctx, redo_requested))
}
pub async fn exec_run_first(run_args: RunArgs, runtime: Runtime) -> Result<(RunRedoCtx, bool)> {
let hub = get_hub();
let cmd_agent_name = &run_args.cmd_agent_name;
let agent = find_agent(cmd_agent_name, &runtime, None)?;
let run_options = RunTopAgentParams::new(run_args)?;
if run_options.base_run_options().open() {
let path = SPath::from(agent.file_path());
if let Err(err) = editor::open_file_auto(&path) {
info!("Cannot open agent file.\nCause: {err}")
}
}
let agent_win_name = text::truncate_left_with_ellipsis(agent.name(), 22, "..");
term::set_window_name(&agent_win_name);
match do_run(&run_options, &runtime, &agent).await {
Ok(run_agent_res) => {
let redo_requested = run_agent_res.redo_requested;
return Ok((
RunRedoCtx::new(
runtime,
agent,
run_options.clone(),
redo_requested,
run_options.flow_redo_count(),
),
redo_requested,
));
}
Err(err) => hub.publish(err).await,
};
Ok((
RunRedoCtx::new(
runtime,
agent,
run_options.clone(),
false,
run_options.flow_redo_count(),
),
false,
))
}
pub async fn exec_run_redo(run_redo_ctx: &RunRedoCtx) -> Option<RunRedoCtx> {
let hub = get_hub();
let runtime = run_redo_ctx.runtime();
let agent = run_redo_ctx.agent();
let run_options = run_redo_ctx.run_options().with_flow_redo_count(run_redo_ctx.flow_redo_count());
let agent = match find_agent(agent.name(), runtime, None) {
Ok(agent) => agent,
Err(err) => {
hub.publish(err).await;
return None;
}
};
match do_run(&run_options, runtime, &agent).await {
Ok(run_agent_res) => Some(RunRedoCtx::new(
runtime.clone(),
agent,
run_options,
run_agent_res.redo_requested,
run_redo_ctx.flow_redo_count(),
)),
Err(err) => {
hub.publish(err).await;
None
}
}
}
pub fn exec_run_watch(redo_ctx: RunRedoCtx) {
tokio::spawn(async move {
let watcher = match watch(redo_ctx.agent().file_path()) {
Ok(watcher) => watcher,
Err(err) => {
get_hub().publish(Error::from(err)).await;
return;
}
};
loop {
match watcher.rx.recv_async().await {
Ok(events) => {
for event in events {
match event.skind {
SEventKind::Modify => {
let hub = get_hub();
hub.publish("\n==== Agent file modified, running command agent again\n").await;
hub.publish(HubEvent::DoExecRedo).await;
}
_ => {
}
}
}
}
Err(e) => {
get_hub().publish(format!("Error receiving event: {e:?}")).await;
break;
}
}
}
});
}
async fn do_run(run_command_options: &RunTopAgentParams, runtime: &Runtime, agent: &Agent) -> Result<RunAgentResponse> {
let inputs = if let Some(on_inputs) = run_command_options.on_inputs() {
Some(into_values(on_inputs)?)
} else if let Some(on_file_globs) = run_command_options.on_file_globs() {
let on_file_globs: Vec<String> = on_file_globs
.iter()
.map(|&glob| {
if !glob.starts_with('/') && !glob.starts_with("./") {
format!("./{glob}")
} else {
glob.to_string()
}
})
.collect();
let on_file_globs: Vec<&str> = on_file_globs.iter().map(|s| s.as_str()).collect();
let files = list_files("./", Some(&on_file_globs), None)?;
let wks_dir = runtime.dir_context().aipack_paths().wks_dir()
.ok_or("Cannot do an 'aip run ...' as no workspace was found.\nDo a 'aip init' in your project folder to initialize a '.aipack/' folder.")?;
let files: Vec<SPath> = files
.into_iter()
.filter_map(|file| {
let absolute_file = file.canonicalize().ok()?;
let absolute_file = absolute_file.try_diff(wks_dir).ok()?;
Some(absolute_file)
})
.collect();
let dir_context = runtime.dir_context();
let file_infos = files
.into_iter()
.map(|f| FileInfo::new(dir_context, f, true))
.collect::<Vec<_>>();
Some(into_values(file_infos)?)
} else {
None
};
let res = run_agent(
runtime,
None,
agent.clone(),
inputs,
run_command_options.base_run_options(),
false,
)
.await?;
Ok(res)
}