use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use crate::event::AgentEvent;
use crate::provider::AnyAgent;
use crate::session::MessageRole;
use crate::ui::avatar;
use crate::ui::colors::c_error;
use crate::ui::compaction::{CompactionPhaseHandle, CompactionThen};
use crate::ui::events::sanitize_output;
use crate::ui::run_handlers::{AgentBuildDeps, RunCtx};
use crate::ui::theme;
#[allow(clippy::too_many_arguments)]
pub(crate) fn submit_resolved_prompt(
ctx: &mut RunCtx<'_>,
deps: &AgentBuildDeps<'_>,
agent: &mut AnyAgent,
hint: Option<String>,
replace: Option<String>,
text: &str,
is_running: &mut bool,
agent_rx: &mut Option<mpsc::Receiver<AgentEvent>>,
agent_abort: &mut Option<JoinHandle<()>>,
agent_interject: &mut Option<mpsc::Sender<()>>,
agent_cancel: &mut Option<mpsc::Sender<()>>,
interjection_queue: &Arc<Mutex<VecDeque<String>>>,
compaction_phase: &mut Option<CompactionPhaseHandle>,
) -> anyhow::Result<()> {
let prompt = if let Some(replacement) = replace {
ctx.renderer
.write_line("[plugin] prompt rewritten:", theme::dim())?;
for line in replacement.lines() {
ctx.renderer
.write_line(&format!(" {}", sanitize_output(line)), theme::dim())?;
}
replacement
} else if let Some(hint) = hint {
format!("{}\n\n{}", hint, text)
} else {
text.to_string()
};
*ctx.last_user_prompt = text.to_string();
let reserve_for_check = ctx.cfg.resolve_reserve_tokens();
let max_tokens_for_check = ctx.session.context_window.saturating_sub(reserve_for_check);
let est_new_tokens = crate::session::Session::estimate_tokens(&prompt);
let preemptive_fired = ctx.cfg.resolve_compact_enabled()
&& crate::ui::slash::preemptive_compaction_due(
ctx.session.total_estimated_tokens,
est_new_tokens,
max_tokens_for_check,
);
let mut deferred_to_compaction = false;
let history = if preemptive_fired {
ctx.renderer.write_line(
"▒░ preemptive compaction (context near limit) ░▒",
theme::accent(),
)?;
match crate::ui::slash::prepare_compaction(
None,
true,
agent,
deps.client,
ctx.renderer,
ctx.session,
ctx.cfg,
) {
Ok(crate::ui::slash::CompactionDecision::Ready(req)) => {
*compaction_phase = Some(crate::ui::compaction::spawn(
*req,
CompactionThen::SendPrompt {
run_prompt: prompt.clone(),
record_text: text.to_string(),
},
));
*is_running = true;
ctx.renderer.set_avatar_state(avatar::AvatarState::Thinking);
deferred_to_compaction = true;
crate::agent::runner::convert_history(ctx.session)
}
Ok(crate::ui::slash::CompactionDecision::NoOp) => {
crate::agent::runner::convert_history(ctx.session)
}
Err(e) => {
ctx.renderer.write_line(
&format!("preemptive compaction failed (will retry reactively if needed): {e}"),
c_error(),
)?;
crate::agent::runner::convert_history(ctx.session)
}
}
} else {
crate::agent::runner::convert_history(ctx.session)
};
if !deferred_to_compaction {
let runner = agent.clone().spawn_runner(
crate::agent::tools::background::prepend_pending_notifications(
&prompt,
deps.bg_store.as_ref(),
),
history,
Some(interjection_queue.clone()),
);
runner.install_into(
agent_rx,
agent_abort,
agent_interject,
agent_cancel,
is_running,
);
ctx.session.add_message(MessageRole::User, text);
crate::ui::begin_snapshot_turn(ctx.session);
ctx.renderer.set_avatar_state(avatar::AvatarState::Idle);
}
Ok(())
}