fix(custom-cli): le bouton Stop annule le tour courant sans fermer la session et cascade l'annulation aux agents délégués — stop_agent suit l'arbre des dépendances actives (cancel_current_turn + préemption runtime + enfants d'exécution), TurnCancel tue le process du tour en cours, autorisation requester/sous-arbre sur idea_stop_agent, fixtures DTO runtime_state/node_id alignées — #257 (QA verte)

This commit is contained in:
2026-08-28 22:57:32 +02:00
parent 9505a3305d
commit 1aabc3d702
12 changed files with 534 additions and 110 deletions

View File

@ -22,7 +22,7 @@ use domain::ports::{
use domain::sandbox::{SandboxEnforcer, SandboxPlan};
use domain::SessionId;
use super::process::{run_turn, SpawnLine};
use super::process::{run_turn_cancellable, SpawnLine, TurnCancel};
/// Résultat du parsing d'une ligne Codex : **zéro ou plusieurs** événements et/ou un
/// id de conversation Codex capté. Miroir de `claude::ParsedLine` (vecteur d'events
@ -377,6 +377,8 @@ pub struct CodexExecSession {
/// Enforcer OS **par instance** (lot LP4-4), passé à [`run_turn`]. `None` ⇒ pas
/// de sandboxing même si un plan est présent (cohérent avec le chemin PTY).
sandbox_enforcer: Option<Arc<dyn SandboxEnforcer>>,
/// Cancel handle for the process backing the current `codex exec` turn.
turn_cancel: TurnCancel,
}
impl CodexExecSession {
@ -473,6 +475,7 @@ impl CodexExecSession {
conversation_id: Mutex::new(seed_conversation_id),
sandbox,
sandbox_enforcer,
turn_cancel: TurnCancel::new(),
}
}
@ -594,6 +597,10 @@ impl AgentSession for CodexExecSession {
// « un run par tour » ⇒ pas de process long survivant : idempotent, no-op.
Ok(())
}
async fn cancel_current_turn(&self) -> Result<(), AgentSessionError> {
self.turn_cancel.cancel().await
}
}
impl CodexExecSession {
@ -631,7 +638,14 @@ impl CodexExecSession {
});
(Some(line_tx), Some(parser))
});
let raw_result = run_turn(&spec, None, self.sandbox_enforcer.as_ref(), line_tap).await;
let raw_result = run_turn_cancellable(
&spec,
None,
self.sandbox_enforcer.as_ref(),
line_tap,
&self.turn_cancel,
)
.await;
if let Some(parser) = parser_thread {
let _ = parser.join();
}