fix(cli): préserve l'affichage des progress legacy sans progressId via clés d'occurrence dédiées — #236

This commit is contained in:
2026-08-21 17:47:05 +02:00
parent fe45b93633
commit aaf628f1ff
2 changed files with 229 additions and 41 deletions

View File

@ -1342,8 +1342,8 @@ describe("CustomAgentChatView", () => {
});
await screen.findByText("done");
expect(screen.getAllByText("Worker ← QA")).toHaveLength(1);
expect(screen.getAllByText("validate")).toHaveLength(1);
expect(screen.getAllByText("Worker ← QA")).toHaveLength(2);
expect(screen.getAllByText("validate")).toHaveLength(2);
expect(screen.queryByText("Appel inter-agent")).toBeNull();
expect(screen.queryByText("reply delivered")).toBeNull();
expect(screen.queryByText("Tool")).toBeNull();
@ -1353,6 +1353,99 @@ describe("CustomAgentChatView", () => {
);
});
it("keeps repeated MCP cycles visible when legacy progress has no progressId", async () => {
let emitChunk: ((chunk: unknown) => void) | null = null;
const agent = {
launchAgentChat: vi.fn(),
reattachAgentChat: vi.fn(async (sessionId: string) => ({
sessionId,
scrollback: [],
})),
sendAgentChat: vi.fn(
(_sessionId: string, _prompt: string, onChunk: (chunk: unknown) => void) =>
new Promise<void>((resolve) => {
emitChunk = (chunk: unknown) => {
onChunk(chunk);
if ((chunk as { kind?: string }).kind === "final") resolve();
};
}),
),
cancelAgentChat: vi.fn(async () => {}),
closeAgentChat: vi.fn(async () => {}),
};
render(
<DIProvider
gateways={{
agent,
system: { pickFile: vi.fn(async () => null) },
} as unknown as Gateways}
>
<CustomAgentChatView
projectId="project-1"
agentId="agent-1"
agentName="Worker"
profile={profile}
cwd="/repo"
nodeId="node-1"
sessionId="chat-session-1"
conversationId="conversation-1"
onSessionId={vi.fn()}
onConversationId={vi.fn()}
/>
</DIProvider>,
);
await waitFor(() =>
expect(agent.reattachAgentChat).toHaveBeenCalledWith(
"chat-session-1",
expect.any(Function),
),
);
fireEvent.change(screen.getByLabelText(/message CLI custom/), {
target: { value: "read many tickets" },
});
fireEvent.click(screen.getByRole("button", { name: "Envoyer" }));
await waitFor(() => expect(emitChunk).not.toBeNull());
act(() => {
for (let index = 1; index <= 8; index += 1) {
emitChunk?.({
kind: "progress" as const,
progress: {
source: "ideaLocal" as const,
kind: "mcp" as const,
stage: "started" as const,
label: "idea_ticket_read",
toolName: "idea_ticket_read",
text: `reading ticket #${index}`,
},
});
emitChunk?.({
kind: "progress" as const,
progress: {
source: "ideaLocal" as const,
kind: "mcp" as const,
stage: "completed" as const,
label: "idea_ticket_read",
toolName: "idea_ticket_read",
text: `read ticket #${index}`,
},
});
}
emitChunk?.({ kind: "final", content: "done" });
});
await screen.findByText("done");
expect(screen.getAllByTestId("chat-tool-progress")).toHaveLength(8);
expect(screen.getAllByText("MCP")).toHaveLength(8);
expect(screen.getAllByText("idea_ticket_read")).toHaveLength(8);
expect(screen.getByText("read ticket #1")).toBeTruthy();
expect(screen.getByText("read ticket #8")).toBeTruthy();
expect(screen.queryByText("reading ticket #1")).toBeNull();
});
it("deduplicates identical entity progress chunks", async () => {
let emitChunk: ((chunk: unknown) => void) | null = null;
const agent = {