Files
next-tjwater-frontend/tests/browser/agent-migrated-tools.e2e.ts
T
jiang ec23d44b02 feat(agent): support Responses steering and project-aware tools
Use the dedicated TJWATER_AGENT_URL and Responses stream protocol. Keep running
turns active while users steer or queue follow-ups and edit pending delivery.
Refresh the model catalog before generation and preserve approval mode selection.

Integrate scoped investigation messaging/presentation, geographic place selection,
current Agent composer styles and supporting workbench contracts.

Validation: 77 focused Vitest checks, 21 browser cases, lint, typecheck and
production build. Preserve direct Server/Agent routing and project authentication.
2026-10-19 18:46:58 +08:00

50 lines
4.6 KiB
TypeScript

import { responsesFixture } from "./support/responses-fixture";
import { expect, test } from "@playwright/test";
import { mockAgentApi } from "./support/mock-agent-api";
import { mockScadaApi } from "./support/mock-scada-api";
import { mockWorkbenchContext } from "./support/mock-workbench-context";
test("chart and history actions send success only after rendering, and final answer replaces process text", async ({ page }) => {
await mockWorkbenchContext(page);
await mockScadaApi(page, [{ device_id: "D1", device_type: "pressure", node_id: "J1", link_id: null, api_query_id: null, measurement_unit: "m", transmission_mode: "test", transmission_frequency: "1min", reliability: 1, x: null, y: null, longitude: 121.48, latitude: 31.1 }]);
await mockAgentApi(page);
const receipts: Array<{ actionId: string; status: string; output: unknown }> = [];
const chart = { title: "监测压力", chart_type: "line", x_data: ["t1", "t2"], series: [{ name: "D1 scada_raw", data: [20, 21] }] };
await page.route("**/api/v1/frontend-action-registry", (route) => route.fulfill({ headers: { "Access-Control-Allow-Origin": "*" }, json: { schema_version: "frontend-action-registry@1", actions: ["show_chart", "view_history", "zoom_to_map", "locate_features"].map((id) => ({ id, version: "frontend-action@1" })) } }));
await page.route("**/api/v1/frontend-actions/*/result", async (route) => {
if (route.request().method() === "OPTIONS") { await route.fulfill({ status: 204, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "*", "Access-Control-Allow-Methods": "POST, OPTIONS" } }); return; }
receipts.push(route.request().postDataJSON());
await route.fulfill({ headers: { "Access-Control-Allow-Origin": "*" }, json: { accepted: true } });
});
await page.route("**/api/v1/responses", async (route) => {
const now = Date.now();
const action = (name: string, params: unknown, actionId: string) => ({ version: "frontend-action@1", actionId, toolCallId: actionId, sessionId: "migrated-session", name, params, issuedAt: now, expiresAt: now + 15000 });
const chunks = [
{ type: "start", messageId: "assistant-migrated" },
{ type: "data-progress", data: { session_id: "migrated-session", id: "business-data", phase: "data", status: "completed", title: "获取业务数据" } },
{ type: "text-start", id: "text" }, { type: "text-delta", id: "text", delta: "正在整理过程说明" }, { type: "text-end", id: "text" },
{ type: "data-frontend_action", data: action("show_chart", chart, "chart-action") },
{ type: "data-frontend_action", data: action("view_history", { element_type: "junction", element_id: "J1", start: "2026-09-01T00:00:00Z", end: "2026-09-01T01:00:00Z", chart }, "history-action") },
{ type: "data-frontend_action", data: action("locate_features", { layer: "scada", feature_ids: ["D1", "missing"] }, "locate-action") },
{ type: "data-frontend_action", data: action("zoom_to_map", { center: [121.48, 31.1], zoom: 14.5 }, "zoom-action") },
{ type: "data-final_answer", data: { session_id: "migrated-session", content: "最终答复:压力曲线已核实。" } },
{ type: "finish", finishReason: "stop" },
];
await route.fulfill({ headers: { "Access-Control-Allow-Origin": "*", "Content-Type": "text/event-stream", "Cache-Control": "no-cache" }, body: responsesFixture(chunks) });
});
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click();
const prompt = page.getByRole("textbox", { name: "询问供水问题,或描述需要处理的任务" }).filter({ visible: true }).first();
await page.waitForFunction(() => Boolean(window.__waterNetworkMap?.getLayer("scada-pressure-hit")));
await prompt.fill("查询历史并展示压力曲线");
await page.getByRole("button", { name: "发送 Agent 指令" }).filter({ visible: true }).first().click();
await expect(page.getByText("最终答复:压力曲线已核实。", { exact: true })).toBeVisible();
await expect(page.getByText("正在整理过程说明", { exact: true })).toBeHidden();
await expect(page.locator('[data-agent-ui-result="chart-action"] svg[role="img"]')).toBeVisible();
await expect(page.locator('[data-agent-ui-result="history-action"] svg[role="img"]')).toBeVisible();
await expect.poll(() => receipts.length).toBe(4);
expect(receipts.find((receipt) => receipt.actionId === "locate-action")?.output).toEqual({ located_ids: ["D1"], missing_ids: ["missing"], fitted: true });
expect(receipts.every((receipt) => receipt.status === "succeeded")).toBe(true);
});