swarm: cancel an agent's turn from the swarm queue
A separate $SWARM.control.<agent> subject carries commands, apart from
the text subject. swarm-controller exposes POST /api/agents/{name}/cancel
as a NATS request; the harness answers whether a turn was actually
stopped, through the same cancel path as the dashboard button. The agent
credential gets subscribe on its control subject and allow_responses to
answer; only the controller may publish there.
Refs #3803
This commit is contained in:
parent
e7ed28b382
commit
fefc565794
11 changed files with 558 additions and 69 deletions
|
|
@ -339,6 +339,35 @@ fn find_claude_child() -> Option<u32> {
|
|||
None
|
||||
}
|
||||
|
||||
/// Stop the turn in flight and say so in the live panel as `by`. Returns
|
||||
/// whether a turn was actually stopped: a cancel that raced an already
|
||||
/// finished turn is `false`, and only a `true` marks the next wake prompt as
|
||||
/// cut off. Shared by the dashboard's `/cancel` and the swarm queue's cancel
|
||||
/// command, so the two cannot disagree about what cancelling is.
|
||||
pub(crate) fn cancel_turn(bus: &Bus, interrupted: &AtomicBool, by: &str) -> bool {
|
||||
let (acted, what) = if let Some(canceller) = bus.turn_canceller() {
|
||||
if canceller.cancel() {
|
||||
(true, "sent session/cancel to the ACP agent".to_owned())
|
||||
} else {
|
||||
(false, "no ACP turn to cancel".to_owned())
|
||||
}
|
||||
} else {
|
||||
match sigint_claude() {
|
||||
SigintOutcome::Signalled => (true, "sent SIGINT to claude".to_owned()),
|
||||
SigintOutcome::NoProcess => (false, "no claude process to interrupt".to_owned()),
|
||||
SigintOutcome::Failed(e) => (false, format!("kill failed: {e}")),
|
||||
}
|
||||
};
|
||||
if acted {
|
||||
// The next turn's wake prompt tells the agent it was cut off mid-work.
|
||||
interrupted.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
bus.emit(crate::events::LiveEvent::Note {
|
||||
text: format!("{by} - {what}"),
|
||||
});
|
||||
acted
|
||||
}
|
||||
|
||||
/// SIGINT this container's harness-spawned claude child, if any
|
||||
/// (best-effort). See [`find_claude_child`] for how it's identified —
|
||||
/// **not** a name-based `pkill claude`, which would also hit an unrelated
|
||||
|
|
|
|||
Loading…
Reference in a new issue