fix(frontend): restaure l'historique durable au retour sur une conversation existante sans session live — freshOnOpen réservé au reset explicite (retiré de LayoutGrid et WebAgentCell), conversationId persistant de la cellule réutilisé au remontage ordinaire avec chargement de l'historique via conversation.readPage (machine savedConversationLoadState idle/loading/loaded/error/notFound, pagination ancrée conservée, écran vide faussement « Nouvelle conversation » éliminé), bannière d'annonces live et fallback de délégation masqués sans session réellement rattachée (liveSessionAttached), /clean et le reset ouvrent explicitement une nouvelle conversation (conversationId: null), erreurs de chargement traitées avec réessai et bouton « Nouvelle conversation » à la place du déliage, composer et pièces jointes désactivés en échec de chargement — #366 (QA verte: npm test ciblé CustomAgentChatView + LayoutGrid.chat + WebAgentCell 3 fichiers 119 tests OK, npm run build OK, git diff --check OK; warning jsdom/canvas connu non bloquant, npm audit: vulnérabilités préexistantes non liées)
This commit is contained in:
@ -288,30 +288,21 @@ describe("CustomAgentChatView", () => {
|
||||
expect(screen.getByTestId("custom-agent-chat-composer").className).toContain("bg-raised/40");
|
||||
});
|
||||
|
||||
it("settles an isolated conversation id without recovered turns as an actionable unavailable state (#307/#314)", async () => {
|
||||
it("restores a durable conversation without starting or sending to the provider (#366)", async () => {
|
||||
const page = deferred<{
|
||||
turns: Array<{ id: string; atMs: number; role: "prompt" | "response"; source: { kind: "human" } | { kind: "agent"; agentId: string }; text: string; textLen: number }>;
|
||||
hasMore: boolean;
|
||||
}>();
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(async () => ({
|
||||
sessionId: "fresh-session",
|
||||
transcriptUnavailableReason: "missingTranscript" as const,
|
||||
})),
|
||||
reattachAgentChat: vi.fn(async (sessionId: string) => ({
|
||||
sessionId,
|
||||
scrollback: [],
|
||||
transcriptUnavailableReason: "missingTranscript" as const,
|
||||
})),
|
||||
launchAgentChat: vi.fn(),
|
||||
reattachAgentChat: vi.fn(),
|
||||
sendAgentChat: vi.fn(async () => {}),
|
||||
cancelAgentChat: vi.fn(async () => {}),
|
||||
closeAgentChat: vi.fn(async () => {}),
|
||||
};
|
||||
|
||||
const onConversationId = vi.fn();
|
||||
const conversation = { readPage: vi.fn(() => page.promise) };
|
||||
render(
|
||||
<DIProvider
|
||||
gateways={{
|
||||
agent,
|
||||
system: { pickFile: vi.fn(async () => null) },
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
<DIProvider gateways={{ agent, conversation, system: { pickFile: vi.fn(async () => null) } } as unknown as Gateways}>
|
||||
<CustomAgentChatView
|
||||
projectId="project-1"
|
||||
agentId="agent-1"
|
||||
@ -320,97 +311,81 @@ describe("CustomAgentChatView", () => {
|
||||
cwd="/repo"
|
||||
nodeId="node-1"
|
||||
sessionId={null}
|
||||
conversationId="orphan-conversation"
|
||||
conversationId="saved-conversation"
|
||||
onSessionId={vi.fn()}
|
||||
onConversationId={onConversationId}
|
||||
onConversationId={vi.fn()}
|
||||
/>
|
||||
</DIProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(agent.launchAgentChat).toHaveBeenCalledWith(
|
||||
"project-1",
|
||||
"agent-1",
|
||||
expect.objectContaining({ conversationId: "orphan-conversation" }),
|
||||
),
|
||||
);
|
||||
expect(
|
||||
await screen.findByText("La conversation liée n’a pas pu être restaurée."),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText("Sa transcription n’est plus disponible après la reprise.")).toBeTruthy();
|
||||
expect(
|
||||
screen.queryByText("Conversation liée — récupération du transcript en cours."),
|
||||
).toBeNull();
|
||||
expect(screen.queryByRole("progressbar")).toBeNull();
|
||||
expect(screen.getByRole("button", { name: "Réessayer" })).toBeTruthy();
|
||||
fireEvent.click(screen.getByRole("button", { name: "Délier la conversation" }));
|
||||
expect(onConversationId).toHaveBeenCalledWith(null);
|
||||
expect(await screen.findByText("Envoyez un message pour démarrer la conversation structurée.")).toBeTruthy();
|
||||
expect(await screen.findByText("Chargement de la conversation…")).toBeTruthy();
|
||||
expect(screen.queryByText("Nouvelle conversation")).toBeNull();
|
||||
page.resolve({
|
||||
turns: [
|
||||
{ id: "p1", atMs: 10, role: "prompt", source: { kind: "human" }, text: "Question sauvegardée", textLen: 20 },
|
||||
{ id: "r1", atMs: 20, role: "response", source: { kind: "agent", agentId: "agent-1" }, text: "Réponse sauvegardée", textLen: 19 },
|
||||
],
|
||||
hasMore: false,
|
||||
});
|
||||
expect(await screen.findByText("Question sauvegardée")).toBeTruthy();
|
||||
expect(screen.getByText("Réponse sauvegardée")).toBeTruthy();
|
||||
expect(agent.launchAgentChat).not.toHaveBeenCalled();
|
||||
expect(agent.reattachAgentChat).not.toHaveBeenCalled();
|
||||
expect(agent.sendAgentChat).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps an empty linked custom CLI continuation usable without explicit transcript loss", async () => {
|
||||
it("keeps a durable load failure distinct and retries without clearing its conversation id", async () => {
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(async () => ({ sessionId: "valid-session" })),
|
||||
reattachAgentChat: vi.fn(async (sessionId: string) => ({
|
||||
sessionId,
|
||||
scrollback: [],
|
||||
})),
|
||||
sendAgentChat: vi.fn(async () => {}),
|
||||
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={null} conversationId="valid-conversation" onSessionId={vi.fn()} onConversationId={vi.fn()} />
|
||||
</DIProvider>,
|
||||
);
|
||||
|
||||
expect(
|
||||
await screen.findByText("Envoyez un message pour démarrer la conversation structurée."),
|
||||
).toBeTruthy();
|
||||
expect(screen.queryByText("La conversation liée n’a pas pu être restaurée.")).toBeNull();
|
||||
});
|
||||
|
||||
it("treats emptyConversation as a normal fresh conversation", async () => {
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(async () => ({
|
||||
sessionId: "fresh-session",
|
||||
transcriptUnavailableReason: "emptyConversation" as const,
|
||||
})),
|
||||
reattachAgentChat: vi.fn(async (sessionId: string) => ({
|
||||
sessionId,
|
||||
scrollback: [],
|
||||
transcriptUnavailableReason: "emptyConversation" as const,
|
||||
})),
|
||||
sendAgentChat: vi.fn(async () => {}),
|
||||
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={null} conversationId="conversation-1" onSessionId={vi.fn()} onConversationId={vi.fn()} />
|
||||
</DIProvider>,
|
||||
);
|
||||
expect(await screen.findByText("Envoyez un message pour démarrer la conversation structurée.")).toBeTruthy();
|
||||
expect(screen.queryByText("La conversation liée n’a pas pu être restaurée.")).toBeNull();
|
||||
});
|
||||
|
||||
it("maps NOT_FOUND to an actionable missing conversation without automatic looping", async () => {
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(async () => { throw { code: "NOT_FOUND", message: "conversation not found" }; }),
|
||||
launchAgentChat: vi.fn(),
|
||||
reattachAgentChat: vi.fn(),
|
||||
sendAgentChat: vi.fn(async () => {}),
|
||||
cancelAgentChat: vi.fn(async () => {}),
|
||||
closeAgentChat: vi.fn(async () => {}),
|
||||
};
|
||||
const conversation = {
|
||||
readPage: vi.fn()
|
||||
.mockRejectedValueOnce(new Error("disk temporarily unavailable"))
|
||||
.mockResolvedValueOnce({
|
||||
turns: [{ id: "p1", atMs: 10, role: "prompt" as const, source: { kind: "human" as const }, text: "Message restauré", textLen: 16 }],
|
||||
hasMore: false,
|
||||
}),
|
||||
};
|
||||
const onConversationId = vi.fn();
|
||||
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={null} conversationId="missing-conversation" onSessionId={vi.fn()} onConversationId={vi.fn()} />
|
||||
<DIProvider gateways={{ agent, conversation, 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={null} conversationId="saved-conversation" onSessionId={vi.fn()} onConversationId={onConversationId} />
|
||||
</DIProvider>,
|
||||
);
|
||||
expect(await screen.findByText("Cette conversation est introuvable dans le stockage disponible.")).toBeTruthy();
|
||||
expect(agent.launchAgentChat).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(await screen.findByText(/Impossible de charger cette conversation sauvegardée/)).toBeTruthy();
|
||||
expect(onConversationId).not.toHaveBeenCalled();
|
||||
fireEvent.click(screen.getByRole("button", { name: "Réessayer" }));
|
||||
expect(await screen.findByText("Message restauré")).toBeTruthy();
|
||||
expect(conversation.readPage).toHaveBeenCalledTimes(2);
|
||||
expect(onConversationId).not.toHaveBeenCalled();
|
||||
expect(agent.launchAgentChat).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps a confirmed missing durable conversation selected until an explicit action", async () => {
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(),
|
||||
reattachAgentChat: vi.fn(),
|
||||
sendAgentChat: vi.fn(async () => {}),
|
||||
cancelAgentChat: vi.fn(async () => {}),
|
||||
closeAgentChat: vi.fn(async () => {}),
|
||||
};
|
||||
const conversation = { readPage: vi.fn(async () => { throw { code: "NOT_FOUND", message: "conversation not found" }; }) };
|
||||
const onConversationId = vi.fn();
|
||||
render(
|
||||
<DIProvider gateways={{ agent, conversation, 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={null} conversationId="missing-conversation" onSessionId={vi.fn()} onConversationId={onConversationId} />
|
||||
</DIProvider>,
|
||||
);
|
||||
expect(await screen.findByText(/Cette conversation sauvegardée est introuvable/)).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: "Réessayer" })).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: "Nouvelle conversation" })).toBeTruthy();
|
||||
expect(onConversationId).not.toHaveBeenCalled();
|
||||
expect(agent.launchAgentChat).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("projects self-restart lifecycle separators in the custom CLI only once", async () => {
|
||||
@ -430,6 +405,7 @@ describe("CustomAgentChatView", () => {
|
||||
<DIProvider gateways={{ agent, system } as unknown as Gateways}>
|
||||
<AnnouncementsProvider projectId="project-1">
|
||||
<CustomAgentChatView
|
||||
freshOnOpen
|
||||
projectId="project-1"
|
||||
agentId="agent-1"
|
||||
agentName="Worker"
|
||||
@ -660,6 +636,7 @@ describe("CustomAgentChatView", () => {
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
<CustomAgentChatView
|
||||
freshOnOpen
|
||||
projectId="project-1"
|
||||
agentId="agent-1"
|
||||
agentName="Worker"
|
||||
@ -708,6 +685,7 @@ describe("CustomAgentChatView", () => {
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
<CustomAgentChatView
|
||||
freshOnOpen
|
||||
projectId="project-1"
|
||||
agentId="agent-1"
|
||||
agentName="Worker"
|
||||
@ -1510,7 +1488,17 @@ describe("CustomAgentChatView", () => {
|
||||
{ kind: "userPrompt" as const, text: "Initial prompt" },
|
||||
{ kind: "final" as const, content: "Initial reply" },
|
||||
];
|
||||
const secondReattach = deferred<{ sessionId: string; scrollback: ReplyChunk[] }>();
|
||||
const conversation = {
|
||||
readPage: vi.fn(async () => ({
|
||||
turns: [
|
||||
{ id: "p1", atMs: 1, role: "prompt" as const, source: { kind: "human" as const }, text: "Initial prompt", textLen: 14 },
|
||||
{ id: "r1", atMs: 2, role: "response" as const, source: { kind: "agent" as const, agentId: "agent-1" }, text: "Initial reply", textLen: 13 },
|
||||
{ id: "p2", atMs: 3, role: "prompt" as const, source: { kind: "human" as const }, text: "Question during graph view", textLen: 26 },
|
||||
{ id: "r2", atMs: 4, role: "response" as const, source: { kind: "agent" as const, agentId: "agent-1" }, text: "Answer restored from replay", textLen: 27 },
|
||||
],
|
||||
hasMore: false,
|
||||
})),
|
||||
};
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(),
|
||||
reattachAgentChat: vi
|
||||
@ -1518,8 +1506,7 @@ describe("CustomAgentChatView", () => {
|
||||
.mockImplementationOnce(async (sessionId: string) => ({
|
||||
sessionId,
|
||||
scrollback,
|
||||
}))
|
||||
.mockImplementationOnce(() => secondReattach.promise),
|
||||
})),
|
||||
detachAgentChat: vi.fn(async () => {}),
|
||||
sendAgentChat: vi.fn(async () => {}),
|
||||
cancelAgentChat: vi.fn(async () => {}),
|
||||
@ -1542,6 +1529,7 @@ describe("CustomAgentChatView", () => {
|
||||
<DIProvider
|
||||
gateways={{
|
||||
agent,
|
||||
conversation,
|
||||
system: { pickFile: vi.fn(async () => null) },
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
@ -1553,17 +1541,11 @@ describe("CustomAgentChatView", () => {
|
||||
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,
|
||||
conversation,
|
||||
system: { pickFile: vi.fn(async () => null) },
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
@ -1575,13 +1557,10 @@ describe("CustomAgentChatView", () => {
|
||||
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();
|
||||
expect(agent.reattachAgentChat).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("drops a stale no-response chunk when replay contains a later real answer (#190)", async () => {
|
||||
@ -2172,7 +2151,53 @@ describe("CustomAgentChatView", () => {
|
||||
expect(screen.getByRole("button", { name: "Mettre en attente" })).toBeTruthy();
|
||||
});
|
||||
|
||||
it("falls back to a fresh launch when reattach reports NOT_FOUND", async () => {
|
||||
it("hides remembered announcements while no live session is attached (#366)", async () => {
|
||||
const system = new MockSystemGateway();
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(),
|
||||
reattachAgentChat: vi.fn(),
|
||||
sendAgentChat: vi.fn(async () => {}),
|
||||
cancelAgentChat: vi.fn(async () => {}),
|
||||
closeAgentChat: vi.fn(async () => {}),
|
||||
};
|
||||
|
||||
render(
|
||||
<DIProvider gateways={{ agent, system } as unknown as Gateways}>
|
||||
<AnnouncementsProvider projectId="project-1">
|
||||
<CustomAgentChatView
|
||||
projectId="project-1"
|
||||
agentId="main"
|
||||
agentName="Main"
|
||||
profile={profile}
|
||||
cwd="/repo"
|
||||
nodeId="node-1"
|
||||
sessionId={null}
|
||||
conversationId={null}
|
||||
onSessionId={vi.fn()}
|
||||
onConversationId={vi.fn()}
|
||||
/>
|
||||
</AnnouncementsProvider>
|
||||
</DIProvider>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
system.emit({
|
||||
type: "agentAnnouncement",
|
||||
projectId: "project-1",
|
||||
requester: "main",
|
||||
target: "architect",
|
||||
ticketId: "delegated-1",
|
||||
text: "ancienne commande shell",
|
||||
atMs: 1,
|
||||
});
|
||||
});
|
||||
|
||||
expect(screen.queryByTestId("announcements-preview")).toBeNull();
|
||||
expect(screen.queryByText("ancienne commande shell")).toBeNull();
|
||||
});
|
||||
|
||||
it("falls back to durable history when a persisted live session is gone", async () => {
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(async () => ({
|
||||
sessionId: "chat-session-2",
|
||||
@ -2181,21 +2206,22 @@ describe("CustomAgentChatView", () => {
|
||||
reattachAgentChat: vi
|
||||
.fn()
|
||||
.mockRejectedValueOnce({ code: "NOT_FOUND", message: "structured session gone" })
|
||||
.mockRejectedValueOnce({ code: "NOT_FOUND", message: "structured session gone" })
|
||||
.mockImplementationOnce(async (sessionId: string) => ({
|
||||
sessionId,
|
||||
scrollback: [],
|
||||
})),
|
||||
.mockRejectedValueOnce({ code: "NOT_FOUND", message: "structured session gone" }),
|
||||
sendAgentChat: vi.fn(() => new Promise<void>(() => {})),
|
||||
cancelAgentChat: vi.fn(async () => {}),
|
||||
closeAgentChat: vi.fn(async () => {}),
|
||||
};
|
||||
const onSessionId = vi.fn();
|
||||
const conversation = { readPage: vi.fn(async () => ({
|
||||
turns: [{ id: "r1", atMs: 1, role: "response" as const, source: { kind: "agent" as const, agentId: "agent-1" }, text: "Durable fallback", textLen: 16 }],
|
||||
hasMore: false,
|
||||
})) };
|
||||
|
||||
render(
|
||||
<DIProvider
|
||||
gateways={{
|
||||
agent,
|
||||
conversation,
|
||||
system: { pickFile: vi.fn(async () => null) },
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
@ -2214,18 +2240,9 @@ describe("CustomAgentChatView", () => {
|
||||
</DIProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(agent.launchAgentChat).toHaveBeenCalledWith("project-1", "agent-1", {
|
||||
cwd: "/repo",
|
||||
rows: 24,
|
||||
cols: 80,
|
||||
conversationId: "conversation-1",
|
||||
nodeId: "node-1",
|
||||
}),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(onSessionId).toHaveBeenCalledWith("chat-session-2"),
|
||||
);
|
||||
expect(await screen.findByText("Durable fallback")).toBeTruthy();
|
||||
expect(agent.launchAgentChat).not.toHaveBeenCalled();
|
||||
expect(onSessionId).toHaveBeenCalledWith(null);
|
||||
expect(screen.queryByText(/structured session gone/)).toBeNull();
|
||||
});
|
||||
|
||||
@ -5657,7 +5674,7 @@ describe("CustomAgentChatView", () => {
|
||||
expect(composer.className).toContain("shrink-0");
|
||||
});
|
||||
|
||||
it("falls back when Tauri surfaces structured session NOT_FOUND as a raw string", async () => {
|
||||
it("falls back to durable history when Tauri reports a missing session as text", async () => {
|
||||
const agent = {
|
||||
launchAgentChat: vi.fn(async () => ({
|
||||
sessionId: "chat-session-2",
|
||||
@ -5670,21 +5687,22 @@ describe("CustomAgentChatView", () => {
|
||||
)
|
||||
.mockRejectedValueOnce(
|
||||
"not found: structured session 69b57638-0ac7-4a79-8252-e0436a3265f6",
|
||||
)
|
||||
.mockImplementationOnce(async (sessionId: string) => ({
|
||||
sessionId,
|
||||
scrollback: [],
|
||||
})),
|
||||
),
|
||||
sendAgentChat: vi.fn(() => new Promise<void>(() => {})),
|
||||
cancelAgentChat: vi.fn(async () => {}),
|
||||
closeAgentChat: vi.fn(async () => {}),
|
||||
};
|
||||
const onSessionId = vi.fn();
|
||||
const conversation = { readPage: vi.fn(async () => ({
|
||||
turns: [{ id: "r1", atMs: 1, role: "response" as const, source: { kind: "agent" as const, agentId: "agent-1" }, text: "Historique durable", textLen: 18 }],
|
||||
hasMore: false,
|
||||
})) };
|
||||
|
||||
render(
|
||||
<DIProvider
|
||||
gateways={{
|
||||
agent,
|
||||
conversation,
|
||||
system: { pickFile: vi.fn(async () => null) },
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
@ -5703,7 +5721,7 @@ describe("CustomAgentChatView", () => {
|
||||
</DIProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() => expect(agent.launchAgentChat).toHaveBeenCalledTimes(1));
|
||||
expect(await screen.findByText("Historique durable")).toBeTruthy();
|
||||
expect(agent.reattachAgentChat).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
"69b57638-0ac7-4a79-8252-e0436a3265f6",
|
||||
@ -5715,13 +5733,8 @@ describe("CustomAgentChatView", () => {
|
||||
expect.any(Function),
|
||||
{ projectId: "project-1", agentId: "agent-1" },
|
||||
);
|
||||
expect(agent.reattachAgentChat).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
"chat-session-2",
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(onSessionId).toHaveBeenCalledWith(null);
|
||||
expect(onSessionId).toHaveBeenCalledWith("chat-session-2");
|
||||
expect(agent.launchAgentChat).not.toHaveBeenCalled();
|
||||
expect(screen.queryByText(/not found: structured session/)).toBeNull();
|
||||
});
|
||||
|
||||
@ -5751,6 +5764,7 @@ describe("CustomAgentChatView", () => {
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
<CustomAgentChatView
|
||||
freshOnOpen
|
||||
projectId="project-1"
|
||||
agentId="agent-1"
|
||||
agentName="Worker"
|
||||
@ -6016,6 +6030,7 @@ describe("CustomAgentChatView", () => {
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
<CustomAgentChatView
|
||||
freshOnOpen
|
||||
projectId="project-1"
|
||||
agentId="agent-1"
|
||||
agentName="Worker"
|
||||
@ -6057,6 +6072,7 @@ describe("CustomAgentChatView", () => {
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
<CustomAgentChatView
|
||||
freshOnOpen
|
||||
projectId="project-1"
|
||||
agentId="agent-1"
|
||||
agentName="Worker"
|
||||
@ -6114,6 +6130,7 @@ describe("CustomAgentChatView", () => {
|
||||
} as unknown as Gateways}
|
||||
>
|
||||
<CustomAgentChatView
|
||||
freshOnOpen
|
||||
projectId="project-1"
|
||||
agentId="agent-1"
|
||||
agentName="Worker"
|
||||
@ -6420,7 +6437,7 @@ describe("CustomAgentChatView", () => {
|
||||
render(
|
||||
<DIProvider gateways={{
|
||||
agent,
|
||||
conversation: { readPage: vi.fn() },
|
||||
conversation: { readPage: vi.fn(async () => ({ turns: history, hasMore: false })) },
|
||||
system: { pickFile: vi.fn(async () => null) },
|
||||
} as unknown as Gateways}>
|
||||
<CustomAgentChatView
|
||||
@ -6452,9 +6469,16 @@ describe("CustomAgentChatView", () => {
|
||||
expect(agent.sendAgentChat).not.toHaveBeenCalled();
|
||||
|
||||
fireEvent.change(screen.getByRole("textbox"), { target: { value: "Continue" } });
|
||||
await waitFor(() =>
|
||||
expect(screen.getByRole("button", { name: "Envoyer" }).hasAttribute("disabled")).toBe(false),
|
||||
);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Envoyer" }));
|
||||
expect(await screen.findByText("Conversation poursuivie")).toBeTruthy();
|
||||
expect(await screen.findByText("New final")).toBeTruthy();
|
||||
await waitFor(() => expect(agent.sendAgentChat).toHaveBeenCalledWith(
|
||||
"resumed-session",
|
||||
"Continue",
|
||||
expect.any(Function),
|
||||
));
|
||||
});
|
||||
|
||||
it("uses /clean for a new conversation and disables conversation changes during a turn", async () => {
|
||||
|
||||
Reference in New Issue
Block a user