use crate::agent::message_router::MessageKind;
use crate::agent::registry::ParentKey;
use crate::db::Connection;
#[derive(Debug)]
pub(crate) enum Cancelled {
Stopped,
Discarded,
NotMine,
}
pub(crate) async fn cancel_round(job_id: &str, caller: &str) -> anyhow::Result<Cancelled> {
let conn = &crate::session::store().conn;
let Some((outcome, place)) = locate(conn, job_id, caller)
.await
.map_err(|e| e.context(not_located(job_id)))?
else {
return Ok(Cancelled::NotMine);
};
crate::round_cancel::cancel(job_id);
crate::agent::registry::AGENT_REGISTRY
.cancel_by_parent_key(&ParentKey::AnalyzeRound(job_id.to_string()));
crate::agent::registry::NON_AGENT_CALLS
.remove_by_parent_key(&ParentKey::AnalyzeRound(job_id.to_string()));
crate::jobs::delete_round_rows(conn, job_id)
.await
.map_err(|e| e.context(not_discarded(job_id)))?;
if let Some(dir) = place {
crate::tools::delegation::release_placed_engine(&dir);
}
tracing::info!(job = %job_id, ?outcome, "Analyze round cancelled");
Ok(outcome)
}
fn not_located(job_id: &str) -> anyhow::Error {
anyhow::anyhow!(
"the cancellation of analysis job {job_id} could not be put in place — \
the round was not touched and carries on"
)
}
fn not_discarded(job_id: &str) -> anyhow::Error {
anyhow::anyhow!(
"the cancellation of analysis job {job_id} could not be put in place — its rows could \
not be removed, so this round's live run delivers nothing but a later start of the \
product may still deliver its result"
)
}
async fn locate(
conn: &Connection,
job_id: &str,
caller: &str,
) -> anyhow::Result<Option<(Cancelled, Option<String>)>> {
if let Some(round) = crate::jobs::analyze_round_owned_by(conn, job_id, caller).await? {
return Ok(Some((Cancelled::Stopped, round.exec_dir)));
}
if let Some(envelope) = crate::jobs::pending_envelope(conn, job_id).await? {
if envelope.kind == MessageKind::AnalyzeToolResult
&& crate::jobs::envelope_target(&envelope) == caller
{
return Ok(Some((Cancelled::Discarded, None)));
}
}
Ok(
(crate::round_cancel::registered_caller(job_id).as_deref() == Some(caller))
.then_some((Cancelled::Stopped, None)),
)
}
#[must_use]
pub(crate) fn answer(outcome: &Cancelled, job_id: &str) -> String {
match outcome {
Cancelled::Stopped => format!(
"Cancelled the analysis round (job {job_id}): its analysts stop and its result will \
not be delivered to this session."
),
Cancelled::Discarded => format!(
"Analysis round (job {job_id}) had already produced its result — the result was \
discarded and will not be delivered to this session."
),
Cancelled::NotMine => format!(
"No analysis round of this session to cancel for job {job_id}: this action stops \
only the quick analysis rounds this session dispatched, and nothing was changed."
),
}
}