fix(chat): le bouton Stop de la CLI custom arrête l'agent en cascade (#187)
Le Stop du CustomAgentChatView n'annulait que le tour courant sans libérer la session ni toucher aux tâches enfants ou appels MCP en cours. Il appelle désormais stop_live_agent sur l'agent vivant, qui: - ajoute le port StopAgentExecutionCascade (best-effort, idempotent), implémenté par OrchestratorService pour annuler les idea_run_in_background rattachés au rendez-vous actif (via BackgroundTaskRunner.cancel); - cascade l'arrêt aux wait-dépendances (stop_turn_watch + preempt) pour interrompre les appels MCP et les attentes inter-agents; - libère et supprime la session structurée. UI: nouvel état "Arrêt en cours..." (bouton disabled + loading) pendant l'arrêt, libération du sessionId, label expliquant la cascade demandée. La Tauri command cancel_agent_chat est alignée sur stop_live_agent + stop_turn_watch agent et dépendances. Tests: SpyBackgroundRunner (cascade n'annule que les tâches rattachées), workstate_actions cascade best-effort, CustomAgentChatView stop+cascade feedback et fallback NOT_FOUND.
This commit is contained in:
@ -534,6 +534,7 @@ export function CustomAgentChatView({
|
||||
useState<ProfileCommandDialogState | null>(null);
|
||||
const [opening, setOpening] = useState(false);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [stopping, setStopping] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const scrollRef = useRef<HTMLDivElement | null>(null);
|
||||
const composerRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
@ -1209,23 +1210,46 @@ export function CustomAgentChatView({
|
||||
}
|
||||
}
|
||||
|
||||
async function cancel() {
|
||||
async function stopAgent() {
|
||||
const sid = sessionRef.current;
|
||||
if (!sid || !agent.cancelAgentChat) return;
|
||||
setBusy(false);
|
||||
setOpening(false);
|
||||
if (!sid || !agent.stopLiveAgent || stopping) return;
|
||||
setStopping(true);
|
||||
setError(null);
|
||||
try {
|
||||
await agent.cancelAgentChat(sid);
|
||||
setTurns((prev) => [...prev, { role: "tool", label: "Tour interrompu." }]);
|
||||
const stopped = await agent.stopLiveAgent(projectId, agentId);
|
||||
setBusy(false);
|
||||
setOpening(false);
|
||||
setCurrentSession(null);
|
||||
publishSessionId(null);
|
||||
setTurns((prev) => [
|
||||
...completeRunningProgress(prev),
|
||||
{
|
||||
role: "tool",
|
||||
label:
|
||||
stopped.kind === "structured"
|
||||
? "Agent arrêté. Cascade d'arrêt demandée pour les tâches et appels MCP liés."
|
||||
: "Agent arrêté.",
|
||||
},
|
||||
]);
|
||||
} catch (e) {
|
||||
if (isNotFound(e)) {
|
||||
setBusy(false);
|
||||
setOpening(false);
|
||||
setCurrentSession(null);
|
||||
publishSessionId(null);
|
||||
setTurns((prev) => [...prev, { role: "tool", label: "Session déjà fermée." }]);
|
||||
setTurns((prev) => [
|
||||
...completeRunningProgress(prev),
|
||||
{ role: "tool", label: "Session déjà arrêtée." },
|
||||
]);
|
||||
return;
|
||||
}
|
||||
setError(describe(e));
|
||||
setTurns((prev) => [
|
||||
...prev,
|
||||
{ role: "error", text: `Arrêt de l'agent échoué: ${describe(e)}` },
|
||||
]);
|
||||
} finally {
|
||||
setStopping(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1511,10 +1535,15 @@ export function CustomAgentChatView({
|
||||
size="sm"
|
||||
variant={busy ? "danger" : undefined}
|
||||
className="shrink-0 whitespace-nowrap"
|
||||
disabled={busy ? !supported || !currentSession : !canSend}
|
||||
onClick={() => (busy ? void cancel() : void send())}
|
||||
disabled={
|
||||
busy
|
||||
? !supported || !currentSession || !agent.stopLiveAgent || stopping
|
||||
: !canSend
|
||||
}
|
||||
loading={stopping}
|
||||
onClick={() => (busy ? void stopAgent() : void send())}
|
||||
>
|
||||
{busy ? "Stop" : "Envoyer"}
|
||||
{stopping ? "Arrêt en cours..." : busy ? "Stop" : "Envoyer"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user