import { expect, test } from "@playwright/test"; import { handleRunStream, mockLangGraphAPI, MOCK_THREAD_ID, } from "./utils/mock-api"; const MOCK_AGENTS = [ { name: "test-agent", description: "A test agent for E2E tests", system_prompt: "You are a test agent.", }, ]; test.describe("Agent chat", () => { test("agent gallery page loads and shows agents", async ({ page }) => { mockLangGraphAPI(page, { agents: MOCK_AGENTS }); await page.goto("/workspace/agents"); // The agent card should appear with the agent name await expect(page.getByText("test-agent")).toBeVisible({ timeout: 15_000, }); }); test("agent chat page loads with input box", async ({ page }) => { mockLangGraphAPI(page, { agents: MOCK_AGENTS }); await page.goto("/workspace/agents/test-agent/chats/new"); // The prompt input textarea should be visible const textarea = page.getByPlaceholder(/how can i assist you/i); await expect(textarea).toBeVisible({ timeout: 15_000 }); }); test("agent chat page shows agent badge", async ({ page }) => { mockLangGraphAPI(page, { agents: MOCK_AGENTS }); await page.goto("/workspace/agents/test-agent/chats/new"); // The agent badge should display in the header (scoped to header to avoid // matching the welcome area which also shows the agent name) await expect( page.locator("header span", { hasText: "test-agent" }), ).toBeVisible({ timeout: 15_000 }); }); test("agent chat can regenerate its latest response", async ({ page }) => { const humanMessage = { type: "human", id: "msg-human-agent", content: [{ type: "text", text: "Original agent question" }], }; const aiMessage = { type: "ai", id: "msg-ai-agent", content: "Custom agent response", }; mockLangGraphAPI(page, { agents: MOCK_AGENTS, threads: [ { thread_id: MOCK_THREAD_ID, title: "Agent conversation", agent_name: "test-agent", messages: [humanMessage, aiMessage], }, ], }); let prepareMessageId: string | undefined; let streamBody: Record | undefined; await page.route( `**/api/threads/${MOCK_THREAD_ID}/runs/regenerate/prepare`, (route) => { prepareMessageId = ( route.request().postDataJSON() as { message_id?: string } ).message_id; return route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ input: { messages: [humanMessage] }, checkpoint: { checkpoint_id: "checkpoint-before-human", checkpoint_ns: "", checkpoint_map: null, }, metadata: { regenerate_from_message_id: aiMessage.id, regenerate_from_run_id: `run-${MOCK_THREAD_ID}`, regenerate_checkpoint_id: "checkpoint-before-human", }, target_run_id: `run-${MOCK_THREAD_ID}`, }), }); }, ); await page.route( `**/api/langgraph/threads/${MOCK_THREAD_ID}/runs/stream`, (route) => { streamBody = route.request().postDataJSON() as Record; return handleRunStream(route); }, ); await page.goto(`/workspace/agents/test-agent/chats/${MOCK_THREAD_ID}`); await expect(page.getByText(aiMessage.content)).toBeVisible({ timeout: 15_000, }); await page.evaluate((selectedText) => { const element = Array.from(document.querySelectorAll("p")).find( (candidate) => candidate.textContent?.includes(selectedText), ); const textNode = element?.firstChild; if (!element || !textNode) { throw new Error("Unable to find the custom agent response"); } const range = document.createRange(); range.selectNodeContents(textNode); const selection = window.getSelection(); selection?.removeAllRanges(); selection?.addRange(range); element.dispatchEvent(new MouseEvent("mouseup", { bubbles: true })); }, aiMessage.content); await expect( page.getByRole("button", { name: "Ask in side chat" }), ).toBeVisible(); await page.keyboard.press("Escape"); const assistantTurn = page.locator("[data-assistant-turn]").last(); await assistantTurn.hover(); await page.getByRole("button", { name: "Regenerate" }).click(); await expect.poll(() => prepareMessageId).toBe(aiMessage.id); await expect.poll(() => streamBody).toBeDefined(); expect(streamBody).toMatchObject({ checkpoint: { checkpoint_id: "checkpoint-before-human", checkpoint_ns: "", checkpoint_map: null, }, metadata: { regenerate_from_message_id: aiMessage.id, regenerate_from_run_id: `run-${MOCK_THREAD_ID}`, regenerate_checkpoint_id: "checkpoint-before-human", }, context: { agent_name: "test-agent", thread_id: MOCK_THREAD_ID, }, }); }); });