fix(cli): restaure la conversation au retour de layout via cache conversationId+sessionId — #217

This commit is contained in:
2026-08-15 19:32:56 +02:00
parent 02715a00b8
commit 581063cf96
3 changed files with 236 additions and 12 deletions

View File

@ -522,6 +522,85 @@ describe("CustomAgentChatView", () => {
expect(screen.getByLabelText(/message CLI custom/).hasAttribute("disabled")).toBe(true);
});
it("restores visible conversation from conversationId cache when layout returns before sessionId", async () => {
let scrollback: ReplyChunk[] = [
{ kind: "userPrompt" as const, text: "Initial prompt" },
{ kind: "final" as const, content: "Initial reply" },
];
const secondReattach = deferred<{ sessionId: string; scrollback: ReplyChunk[] }>();
const agent = {
launchAgentChat: vi.fn(),
reattachAgentChat: vi
.fn()
.mockImplementationOnce(async (sessionId: string) => ({
sessionId,
scrollback,
}))
.mockImplementationOnce(() => secondReattach.promise),
detachAgentChat: vi.fn(async () => {}),
sendAgentChat: vi.fn(async () => {}),
cancelAgentChat: vi.fn(async () => {}),
closeAgentChat: vi.fn(async () => {}),
};
const props = {
projectId: "project-1",
agentId: "agent-1",
agentName: "Worker",
profile,
cwd: "/repo",
nodeId: "node-1",
sessionId: "chat-session-1" as string | null,
conversationId: "conversation-1",
onSessionId: vi.fn(),
onConversationId: vi.fn(),
};
const first = render(
<DIProvider
gateways={{
agent,
system: { pickFile: vi.fn(async () => null) },
} as unknown as Gateways}
>
<CustomAgentChatView {...props} />
</DIProvider>,
);
expect(await screen.findByText("Initial reply")).toBeTruthy();
first.unmount();
await waitFor(() => expect(agent.detachAgentChat).toHaveBeenCalledWith("chat-session-1"));
scrollback = [
{ kind: "userPrompt" as const, text: "Initial prompt" },
{ kind: "final" as const, content: "Initial reply" },
{ kind: "userPrompt" as const, text: "Question during graph view" },
{ kind: "final" as const, content: "Answer restored from replay" },
];
render(
<DIProvider
gateways={{
agent,
system: { pickFile: vi.fn(async () => null) },
} as unknown as Gateways}
>
<CustomAgentChatView {...props} sessionId={null} />
</DIProvider>,
);
expect(screen.getByText("Initial reply")).toBeTruthy();
expect(agent.launchAgentChat).not.toHaveBeenCalled();
expect(screen.getByRole("button", { name: "Envoyer" }).hasAttribute("disabled")).toBe(true);
act(() => {
secondReattach.resolve({ sessionId: "chat-session-1", scrollback });
});
expect(await screen.findByText("Answer restored from replay")).toBeTruthy();
expect(screen.getByText("Question during graph view")).toBeTruthy();
expect(agent.launchAgentChat).not.toHaveBeenCalled();
});
it("drops a stale no-response chunk when replay contains a later real answer (#190)", async () => {
const agent = {
launchAgentChat: vi.fn(),