fix(application,domain,infrastructure,web-server,app-tauri,frontend): arrêt d'agent fiable avec cascade sur l'arbre de propriété et statut cohérent — #320 (QA verte)
Symptôme: stopper un agent (ex Main sur UnityPlugin) laissait des travaux poursuivre, la cascade n'atteignait pas les agents lancés et la pastille restait orange pendant que l'agent continuait à en appeler d'autres. - barrière d'admission par génération d'exécution (ExecutionControl): un stop ferme l'admission de tout le sous-arbre propriété/attente AVANT toute annulation asynchrone — plus aucune nouvelle action inter-agents après stop - arbre de propriété durable en-process (launched_by) + dépendances d'attente actives: la cascade couvre transitivement agents et travaux lancés - commandes d'un agent arrêté rejetées (AppError::AgentStopped); stop lui-même admis pour rester idempotent; réactivation sur relance humaine (génération +1) et enregistrement du propriétaire au spawn - admission exposée aux adaptateurs hors commandes cœur (tickets, templates, plugins) via ensure_agent_execution_active; MCP server/tools, web-server et commandes Tauri alignés - cohérence live-state: statut Idle avec intent « Arrêté » ou « Arrêt incomplet — Certains travaux sont encore actifs » selon l'issue de la cascade; workstate et surfaces UI (AgentsPanel, LayoutGrid, ProjectWorkStatePanel) reflètent l'état réel, plus de pastille orange fantôme - tests: orchestrator_service (cascade/générations/idempotence), workstate_actions, background_task_cancel, error_codes, agents, layout, workstate QA verte sur fix/320-agent-stop-cascade. Aucun push.
This commit is contained in:
@ -302,6 +302,8 @@ pub enum OrchestratorCommand {
|
||||
context: Option<String>,
|
||||
/// Desired visibility for the launched session.
|
||||
visibility: OrchestratorVisibility,
|
||||
/// Authenticated caller when the launch originates from an agent tool.
|
||||
requester: Option<AgentId>,
|
||||
},
|
||||
/// Stop/cancel a running agent.
|
||||
StopAgent {
|
||||
@ -587,6 +589,7 @@ impl OrchestratorRequest {
|
||||
profile: Some(self.require("profile", action, self.profile.as_deref())?),
|
||||
context: self.context.as_ref().filter(|c| !c.is_empty()).cloned(),
|
||||
visibility: self.parse_visibility(action)?,
|
||||
requester: self.optional_requester(action)?,
|
||||
}),
|
||||
"agent.run" => Ok(OrchestratorCommand::SpawnAgent {
|
||||
name: self.require_target_agent(action)?,
|
||||
@ -602,6 +605,7 @@ impl OrchestratorRequest {
|
||||
.filter(|c| !c.is_empty())
|
||||
.cloned(),
|
||||
visibility: self.parse_visibility(action)?,
|
||||
requester: self.optional_requester(action)?,
|
||||
}),
|
||||
"stop_agent" => Ok(OrchestratorCommand::StopAgent {
|
||||
name: self.require_name(action)?,
|
||||
@ -981,6 +985,7 @@ mod tests {
|
||||
profile: Some("claude-code".to_owned()),
|
||||
context: Some("agents/dev-backend.md".to_owned()),
|
||||
visibility: OrchestratorVisibility::Background,
|
||||
requester: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -995,6 +1000,7 @@ mod tests {
|
||||
profile: Some("claude-code".to_owned()),
|
||||
context: None,
|
||||
visibility: OrchestratorVisibility::Background,
|
||||
requester: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -1014,6 +1020,7 @@ mod tests {
|
||||
visibility: OrchestratorVisibility::Visible {
|
||||
node_id: NodeId::from_uuid(node)
|
||||
},
|
||||
requester: None,
|
||||
}
|
||||
);
|
||||
|
||||
@ -1053,6 +1060,7 @@ mod tests {
|
||||
profile: None,
|
||||
context: Some("Analyse".to_owned()),
|
||||
visibility: OrchestratorVisibility::Background,
|
||||
requester: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -1072,6 +1080,7 @@ mod tests {
|
||||
visibility: OrchestratorVisibility::Visible {
|
||||
node_id: NodeId::from_uuid(node)
|
||||
},
|
||||
requester: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user