merge feature/91-rendezvous-toast-label dans develop

Ticket #91 — libellé explicite « Appel X -> Y terminé/en échec/annulé »
pour les notifications de fin de background task issues d'un rendez-vous
inter-agent. Frontend pur, tests annoncés verts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 16:49:26 +02:00
2 changed files with 64 additions and 3 deletions

View File

@ -266,7 +266,7 @@ describe("ProjectsView — LS7 conversation viewer integration", () => {
});
const toast = await screen.findByRole("button", {
name: /Main -> DevBackend completed/i,
name: /Appel Main -> DevBackend terminé/i,
});
expect(within(toast).getByText("Task task-ren")).toBeTruthy();
@ -277,10 +277,57 @@ describe("ProjectsView — LS7 conversation viewer integration", () => {
).toBeTruthy();
expect(await screen.findByText("contenu du fil ouvert")).toBeTruthy();
expect(
screen.queryByRole("button", { name: /Main -> DevBackend completed/i }),
screen.queryByRole("button", { name: /Appel Main -> DevBackend terminé/i }),
).toBeNull();
});
it("labels rendezvous failure and cancellation toasts with explicit call attribution", async () => {
const project = new MockProjectGateway();
const created = await project.createProject("alpha", "/p/a");
const agent = new MockAgentGateway();
const system = new MockSystemGateway();
const requester = await agent.createAgent(created.id, {
name: "Main",
profileId: "codex",
});
const target = await agent.createAgent(created.id, {
name: "DevBackend",
profileId: "codex",
});
renderView(project, { agent, system });
await openProjectAndWorkTab("/p/a");
system.emit({
type: "backgroundTaskChanged",
projectId: created.id,
agentId: target.id,
taskId: "task-rendezvous-failed",
state: "failed",
requesterAgentId: requester.id,
targetAgentId: target.id,
});
system.emit({
type: "backgroundTaskChanged",
projectId: created.id,
agentId: target.id,
taskId: "task-rendezvous-cancelled",
state: "cancelled",
requesterAgentId: requester.id,
targetAgentId: target.id,
});
expect(
await screen.findByRole("button", {
name: /Appel Main -> DevBackend en échec/i,
}),
).toBeTruthy();
expect(
await screen.findByRole("button", {
name: /Appel Main -> DevBackend annulé/i,
}),
).toBeTruthy();
});
it("keeps the generic background-task toast when rendezvous agent ids are absent", async () => {
const project = new MockProjectGateway();
const created = await project.createProject("alpha", "/p/a");

View File

@ -135,6 +135,20 @@ function agentLabel(agents: Agent[], agentId: string): string {
);
}
function rendezvousToastStateLabel(state: string): string {
switch (state) {
case "completed":
case "delivered":
return "terminé";
case "failed":
return "en échec";
case "cancelled":
return "annulé";
default:
return state;
}
}
export function ProjectsView() {
const vm = useProjects();
const {
@ -274,7 +288,7 @@ export function ProjectsView() {
taskId: event.taskId,
state: event.state,
title: labels
? `${labels.requester} -> ${labels.target} ${event.state}`
? `Appel ${labels.requester} -> ${labels.target} ${rendezvousToastStateLabel(event.state)}`
: `Background task ${event.state}`,
subtitle: labels
? `Task ${shortTaskId(event.taskId)}`