import { expect, test } from "@playwright/test"; import { captureScreenshot, completeOnboarding, rpc, signup, waitForChatComposer } from "./helpers"; test("main bot delegates a task that a specialist works on visibly in the main conversation", async ({ page, }, testInfo) => { const stamp = Date.now(); await signup(page, `delegation-${stamp}@rakazo.test`, "password12", "Delegation E2E"); await completeOnboarding(page); const researcher = await rpc<{ id: string }>(page, "bots/create", { name: "Researcher", title: "", description: "", instructions: "", notifyOnFinish: true, }); await page.reload(); await waitForChatComposer(page); const composer = page.getByRole("combobox", { name: "Message" }); await composer.fill("delegate to the bot named Researcher: collect three owl facts"); await composer.press("Enter"); // The task is reported in the main conversation, wherever the request was made. let mainGroupId = ""; await expect .poll( async () => { const groups = await rpc>(page, "groups/list", {}); mainGroupId = groups.find((group) => group.kind === "main")?.id ?? ""; return mainGroupId; }, { timeout: 60_000 }, ) .not.toBe(""); await page.goto(`/app/g/${mainGroupId}`); await waitForChatComposer(page); const transcript = page.getByTestId("transcript"); const card = transcript.getByTestId("delegated-task-card"); await expect(card).toBeVisible({ timeout: 30_000 }); await expect(card).toContainText("Researcher"); await expect(card).toContainText("collect three owl facts"); // The specialist joined the conversation and its work appears with it as the sender. await expect( transcript.getByText("done. i handled: collect three owl facts").first(), ).toBeVisible({ timeout: 60_000 }); await expect(transcript.getByText("Researcher", { exact: true }).first()).toBeVisible(); const snapshot = await rpc<{ members?: Array<{ botId: string }> }>(page, "threads/get", { groupId: mainGroupId, }); expect(snapshot.members?.map((member) => member.botId)).toContain(researcher.id); // The card follows the task live, and the main bot closes it in the same conversation. await expect(card).toHaveAttribute("data-status", "done", { timeout: 60_000 }); await expect(card).toContainText("Done"); await expect( transcript.getByText("closing the task: collect three owl facts.").first(), ).toBeVisible({ timeout: 60_000 }); await captureScreenshot(page, testInfo, "delegation-task-closed"); // The brief stays folded until asked for. const brief = card.locator("summary + div"); await expect(brief).toBeHidden(); await card.locator("summary").click(); await expect(brief).toContainText("collect three owl facts"); const tasks = await rpc>( page, "tasks/list", {}, ); expect(tasks).toEqual([ expect.objectContaining({ title: "collect three owl facts", status: "done" }), ]); expect(tasks[0]?.result).toContain("done. i handled: collect three owl facts"); });