refactor: consolidate requests and finalize agent tool states
Share project JSON transport, interaction replies and report selectors. Settle tool progress consistently for direct streams, reconnects and history, preserving failure reasons and stopped state.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { createServer } from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { mockAgentApi } from "./support/mock-agent-api";
|
||||
import { mockWorkbenchContext } from "./support/mock-workbench-context";
|
||||
|
||||
for (const status of ["completed", "error", "aborted"] as const) {
|
||||
test(`tool progress settles after reconnect and reopening (${status})`, async ({ page }, testInfo) => {
|
||||
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||
await mockWorkbenchContext(page);
|
||||
const sessionId = `tool-terminal-${status}`;
|
||||
const title = `工具终态核查 ${status}`;
|
||||
await mockAgentApi(page, { sessions: [{ session_id: sessionId, title, created_at: Date.now(), updated_at: Date.now() }] });
|
||||
const headers = { "Access-Control-Allow-Origin": "*" };
|
||||
const messages = [{ id: "tool-answer", role: "assistant", parts: [
|
||||
{ type: "text", text: "已查到部分压力记录。" },
|
||||
{ type: "data-progress", data: { id: "tool", phase: "tool", title: "正在处理", status: "running", tool: { name: "query_pressure", input: { node_id: 12 } } } },
|
||||
] }];
|
||||
let settled = false;
|
||||
let finish: (() => void) | undefined;
|
||||
const server = createServer((_request, response) => {
|
||||
response.writeHead(200, { ...headers, "Content-Type": "text/event-stream" });
|
||||
response.write(`event: state\ndata: ${JSON.stringify({ session_id: sessionId, messages, is_streaming: true, run_status: "running" })}\n\n`);
|
||||
finish = () => {
|
||||
settled = true;
|
||||
const type = status === "completed" ? "done" : status === "aborted" ? "aborted" : "error";
|
||||
const data = { session_id: sessionId, status, message: status === "error" ? "压力查询连接失败" : "请求已中断" };
|
||||
// Legacy subscriptions may terminate without a separate run_status event.
|
||||
response.end(`event: ${type}\ndata: ${JSON.stringify(data)}\n\n`);
|
||||
};
|
||||
});
|
||||
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||
await page.route(`**/api/v1/session/${sessionId}?**`, (route) => route.fulfill({ headers, json: {
|
||||
session_id: sessionId, title, purpose: "ordinary_chat", status: "active",
|
||||
is_streaming: !settled, run_status: settled ? status : "running", messages,
|
||||
} }));
|
||||
await page.route(`**/api/v1/session/${sessionId}/stream**`, (route) => route.continue({ url: `http://127.0.0.1:${(server.address() as AddressInfo).port}` }));
|
||||
const panel = page.getByRole("complementary", { name: "Agent 命令面板" });
|
||||
const answer = panel.locator('[data-agent-message-id="tool-answer"]');
|
||||
const icon = answer.locator('[data-agent-tool] [data-progress-status]');
|
||||
const open = async () => {
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click();
|
||||
await panel.getByRole("button", { name: "打开 Agent 历史记录" }).click();
|
||||
await page.locator("button.agent-history-session-trigger").filter({ hasText: title }).click();
|
||||
};
|
||||
try {
|
||||
await open();
|
||||
await expect(icon).toHaveAttribute("data-progress-status", "running");
|
||||
await expect.poll(() => Boolean(finish)).toBe(true);
|
||||
finish!();
|
||||
await answer.getByRole("button", { name: "查看处理过程", exact: true }).click();
|
||||
const expectedStatus = status === "aborted" ? "cancelled" : status;
|
||||
await expect(icon).toHaveAttribute("data-progress-status", expectedStatus);
|
||||
await expect(answer.locator('[data-progress-status="running"]')).toHaveCount(0);
|
||||
if (status === "error") await expect(answer.getByRole("status").filter({ hasText: "压力查询连接失败" })).toBeVisible();
|
||||
await answer.screenshot({ path: testInfo.outputPath(`${status}-settled.png`), animations: "disabled" });
|
||||
await open();
|
||||
await answer.getByRole("button", { name: "查看处理过程", exact: true }).click();
|
||||
await expect(icon).toHaveAttribute("data-progress-status", expectedStatus);
|
||||
await expect(answer.locator('[data-progress-status="running"]')).toHaveCount(0);
|
||||
if (status === "aborted") await expect(icon).toHaveAttribute("aria-label", "已中止");
|
||||
await answer.screenshot({ path: testInfo.outputPath(`${status}-reopened.png`), animations: "disabled" });
|
||||
} finally {
|
||||
server.closeAllConnections();
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user