diff --git a/frontend/src/features/agents/CustomAgentChatView.test.tsx b/frontend/src/features/agents/CustomAgentChatView.test.tsx index 4e7357e9..f9d45687 100644 --- a/frontend/src/features/agents/CustomAgentChatView.test.tsx +++ b/frontend/src/features/agents/CustomAgentChatView.test.tsx @@ -1598,7 +1598,7 @@ describe("CustomAgentChatView", () => { expect(screen.getByText("Progress").parentElement?.textContent).toContain("Terminé"); }); - it("does not append late progress chunks after the final answer", async () => { + it("renders late progress chunks after the final answer without reopening the turn", async () => { let emitChunk: ((chunk: unknown) => void) | null = null; const agent = { launchAgentChat: vi.fn(), @@ -1672,7 +1672,10 @@ describe("CustomAgentChatView", () => { }); }); - expect(screen.queryByText("idea_ticket_read")).toBeNull(); + expect(screen.getByText("done")).toBeTruthy(); + expect(screen.getByText("idea_ticket_read")).toBeTruthy(); + expect(screen.getByRole("button", { name: "Envoyer" })).toBeTruthy(); + expect(screen.queryByRole("button", { name: "Stop" })).toBeNull(); }); it("shows slash-command suggestions from the gateway, filters by prefix, and inserts the selected command", async () => { diff --git a/frontend/src/features/agents/CustomAgentChatView.tsx b/frontend/src/features/agents/CustomAgentChatView.tsx index 126f5c33..113f9ada 100644 --- a/frontend/src/features/agents/CustomAgentChatView.tsx +++ b/frontend/src/features/agents/CustomAgentChatView.tsx @@ -425,19 +425,21 @@ function isRecoverableNoResponseTurn(turn: ChatTurn | undefined): boolean { } function turnsIndicateBusy(state: ChatViewState): boolean { + let sawOpenActivity = false; for (let index = state.turns.length - 1; index >= 0; index -= 1) { const turn = state.turns[index]; if (turn.role === "final" || turn.role === "error") return false; - if (turn.role === "agent" && turn.pending) return true; + if (turn.role === "user") return sawOpenActivity; + if (turn.role === "agent" && turn.pending) sawOpenActivity = true; if ( turn.role === "progress" && !turn.settled && progressStageBucket(turn.progress) !== "completed" ) { - return true; + sawOpenActivity = true; } } - return false; + return sawOpenActivity; } function insertTextAtSelection( @@ -610,6 +612,14 @@ function foldChunk( if (isRecoverableNoResponseTurn(last) && raw.kind !== "error") { return foldChunk({ ...state, turns: turns.slice(0, -1) }, raw, receivedAtMs); } + if (raw.kind === "progress") { + return appendProgress(state, normalizeProgress(raw.progress) ?? { + source: "ideaLocal", + kind: "other", + stage: "info", + label: unknownChunkLabel(raw), + }); + } return state; } switch (raw.kind) {