hive-agent: dashboard Cancel and idle stalls for ACP agents
`/api/cancel` stopped a turn only by SIGINTing a child process whose argv0 is `claude`, so on an ACP agent it reported "no claude process to interrupt" and the turn ran on. The serve loop now stores the session's canceller on the `Bus` when the runtime has one, and `/api/cancel` uses it: the agent is sent `session/cancel`, and the next wake prompt carries the interrupted hint, as for a signalled claude turn. Without a canceller (claude), the SIGINT path is untouched. An ACP turn stopped by the idle watchdog (`HIVE_TURN_IDLE_SECS`) becomes `TurnError::AgentStall(note)`, handled like `ApiStall`: park for `HIVE_STALL_SLEEP_SECS`, requeue, and record `api_stall`. The TurnEnd note is the runtime's message (how long the agent was silent, whether it had to be killed, and that a silently retried provider error such as HTTP 429 looks like this), not the claude-specific `ApiStall` text. A cancel the agent ignores is a `Failed` turn. Refs #4391
This commit is contained in:
parent
bcbeb8ac9c
commit
91e47732a6
7 changed files with 115 additions and 9 deletions
|
|
@ -52,6 +52,22 @@ pub(super) async fn post_send(
|
|||
}
|
||||
|
||||
pub(super) async fn post_cancel_turn(State(state): State<AppState>) -> Response {
|
||||
if let Some(canceller) = state.bus.turn_canceller() {
|
||||
let note = if canceller.cancel() {
|
||||
// Same as a signalled claude turn: the next wake prompt says it
|
||||
// was cut off.
|
||||
state
|
||||
.interrupted
|
||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
"operator: /cancel — sent session/cancel to the ACP agent"
|
||||
} else {
|
||||
"operator: /cancel — no ACP turn to cancel"
|
||||
};
|
||||
state
|
||||
.bus
|
||||
.emit(crate::events::LiveEvent::Note { text: note.into() });
|
||||
return (axum::http::StatusCode::OK, "ok").into_response();
|
||||
}
|
||||
let out = super::sigint_claude().await;
|
||||
let note = match out {
|
||||
SigintOutcome::Signalled => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue