use compact_str::CompactString;
use crossterm::style::Color;
use tokio::sync::mpsc;
use crate::agent::tools::background::BackgroundStore;
use crate::event::AgentEvent;
use crate::provider::AnyAgent;
use crate::session::MessageRole;
use crate::ui::agent_io::persist_turn_to_db;
use crate::ui::colors::{c_agent, c_error};
use crate::ui::run_handlers::RunCtx;
use crate::ui::theme;
use crate::ui::tool_display::close_tool_chamber_if_open;
#[allow(clippy::too_many_arguments)]
pub(crate) async fn handle_interjected(
ctx: &mut RunCtx<'_>,
partial_response: CompactString,
tokens: u64,
was_reasoning: &mut bool,
is_running: &mut bool,
agent: &AnyAgent,
agent_rx: &mut Option<mpsc::Receiver<AgentEvent>>,
agent_abort: &mut Option<tokio::task::JoinHandle<()>>,
agent_interject: &mut Option<mpsc::Sender<()>>,
agent_cancel: &mut Option<mpsc::Sender<()>>,
interjection_queue: &std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<String>>>,
bg_store: &Option<BackgroundStore>,
) -> anyhow::Result<()> {
*was_reasoning = false;
close_tool_chamber_if_open(ctx.renderer, ctx.last_tool_name, ctx.tool_chamber_open)?;
if !ctx.response_buf.is_empty() {
ctx.renderer.stream(ctx.response_buf, c_agent(), true);
ctx.renderer.render_viewport()?;
}
ctx.renderer.commit_stream();
ctx.renderer.write_line("", Color::White)?;
ctx.renderer.write_line(
"(interjected — stopped at last tool-result boundary)",
theme::dim(),
)?;
ctx.renderer.write_line("", Color::White)?;
if !partial_response.is_empty() {
persist_turn_to_db(
ctx.session,
ctx.last_user_prompt,
&partial_response,
ctx.tool_calls_buf,
);
ctx.session.add_message_with_tool_calls(
MessageRole::Assistant,
&partial_response,
std::mem::take(ctx.tool_calls_buf),
);
ctx.session.total_tokens = ctx.session.total_tokens.saturating_add(tokens);
} else {
ctx.tool_calls_buf.clear();
}
*ctx.tool_calls_this_run = 0;
*ctx.agent_line_started = false;
ctx.response_buf.clear();
*ctx.response_start_line = None;
ctx.reasoning_buf.clear();
*ctx.reasoning_start_line = None;
if !ctx.cli.no_session
&& let Err(e) = crate::session::storage::save_session(ctx.session)
{
ctx.renderer.write_line(
&format!("warning: failed to save session: {}", e),
c_error(),
)?;
}
*is_running = false;
if let Some(h) = agent_abort.take() {
h.abort();
}
*agent_rx = None;
*agent_interject = None;
*agent_cancel = None;
if !interjection_queue.lock().unwrap().is_empty() {
let queued: Vec<String> = interjection_queue.lock().unwrap().drain(..).collect();
let combined = queued.join("\n\n");
ctx.last_user_prompt.clone_from(&combined);
let history = crate::agent::runner::convert_history(ctx.session);
ctx.session.add_message(MessageRole::User, &combined);
let runner = agent.clone().spawn_runner(
crate::agent::tools::background::prepend_pending_notifications(
&combined,
bg_store.as_ref(),
),
history,
Some(interjection_queue.clone()),
);
runner.install_into(
agent_rx,
agent_abort,
agent_interject,
agent_cancel,
is_running,
);
}
Ok(())
}