feat: expand intelligent investigation workspace
This commit is contained in:
@@ -4,29 +4,36 @@ 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 }) => {
|
||||
test("unified chart and map commands send success only after rendering, and final answer replaces process text", async ({ page }, testInfo) => {
|
||||
test.setTimeout(60000);
|
||||
await mockWorkbenchContext(page);
|
||||
await page.route("**/runtime-config.js", (route) => route.fulfill({ contentType: "application/javascript", body: 'globalThis.__TJWATER_CONFIG__ = { TJWATER_AUTH_MODE:"disabled", TJWATER_SERVER_API_BASE_URL:"https://tjwater-api.invalid", TJWATER_AGENT_URL:"http://127.0.0.1:8787", TJWATER_MAP_URL:"https://workbench-map.invalid/geoserver", TJWATER_GEOSERVER_WORKSPACE:"tjwater_next", TJWATER_WORKBENCH_RUNTIME_MODE:"auto", TJWATER_ENABLE_MSW:"false", TJWATER_ENABLE_DEV_PANEL:"true" };' }));
|
||||
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-action-registry", (route) => route.fulfill({ headers: { "Access-Control-Allow-Origin": "*" }, json: { schema_version: "frontend-action-registry@2", actions: ["open_chart", "close_chart", "highlight_features", "clear_highlights", "zoom_to_map", "locate_features"].map((id) => ({ id, version: "frontend-action@2" })) } }));
|
||||
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 } });
|
||||
});
|
||||
let responseNumber = 0;
|
||||
await page.route("**/api/v1/responses", async (route) => {
|
||||
responseNumber += 1;
|
||||
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 action = (command: Record<string, unknown>, actionId: string) => ({ version: "frontend-action@2", actionId, toolCallId: actionId, sessionId: "migrated-session", command, issuedAt: now, expiresAt: now + 15000 });
|
||||
const commands = responseNumber === 2
|
||||
? [{ action: "clear_highlights" }, { action: "close_chart", chart_id: "chat-pressure" }]
|
||||
: [{ action: "highlight_features", layer: "scada", feature_ids: ["D1"], effect: "pulse" },
|
||||
{ action: "open_chart", chart_id: "chat-pressure", chart, evidence_refs: [] }];
|
||||
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") },
|
||||
...commands.map((command, index) => ({ type: "data-frontend_action", data: action(command, `command-${responseNumber}-${index}`) })),
|
||||
...(responseNumber === 1 ? [{ type: "data-frontend_action", data: action({ action: "locate_features", layer: "scada", feature_ids: ["D1", "missing"] }, "locate-action") }] : []),
|
||||
...(responseNumber === 1 ? [{ type: "data-frontend_action", data: action({ 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" },
|
||||
];
|
||||
@@ -40,10 +47,47 @@ test("chart and history actions send success only after rendering, and final ans
|
||||
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();
|
||||
const display = page.getByLabel("对话展示", { exact: true });
|
||||
await expect(display.locator('[data-investigation-chart="chat-pressure"] 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);
|
||||
|
||||
const sourceSize = (source: string) => page.evaluate(async (source) => {
|
||||
const data = await (window.__waterNetworkMap?.getSource(source) as {
|
||||
getData: () => Promise<{ features: unknown[] }>
|
||||
} | undefined)?.getData();
|
||||
return data?.features.length ?? 0;
|
||||
}, source);
|
||||
await expect.poll(() => sourceSize("chat-presentation-highlights")).toBe(1);
|
||||
await page.getByRole("button", { name: "切换地图 Dev Panel" }).click();
|
||||
const tools = page.getByTestId("investigation-dev-tools");
|
||||
await tools.getByLabel("调查展示 JSONL", { exact: true }).fill([
|
||||
{ record_type: "presentation", command: { action: "highlight_features", layer: "scada", feature_ids: ["D1"], effect: "pulse" } },
|
||||
{ record_type: "presentation", command: { action: "open_chart", chart_id: "dev-pressure", chart, evidence_refs: [] } },
|
||||
].map((record) => JSON.stringify(record)).join("\n"));
|
||||
await tools.getByRole("button", { name: "执行本地预览", exact: true }).click();
|
||||
await expect(page.getByLabel("本地预览展示", { exact: true }).locator('[data-investigation-chart="dev-pressure"]')).toBeVisible();
|
||||
await expect.poll(() => sourceSize("preview-presentation-highlights")).toBe(1);
|
||||
await page.screenshot({ path: testInfo.outputPath("unified-chat-dev.png") });
|
||||
await page.getByRole("button", { name: "切换地图 Dev Panel" }).click();
|
||||
const send = async (text: string) => {
|
||||
await prompt.fill(text);
|
||||
await page.getByRole("button", { name: "发送 Agent 指令" }).filter({ visible: true }).first().click();
|
||||
};
|
||||
await send("清除本轮对话展示");
|
||||
await expect.poll(() => receipts.length).toBe(6);
|
||||
await expect(display.locator('[data-investigation-chart="chat-pressure"]')).toHaveCount(0);
|
||||
await expect.poll(() => sourceSize("chat-presentation-highlights")).toBe(0);
|
||||
await expect.poll(() => sourceSize("preview-presentation-highlights")).toBe(1);
|
||||
await send("重新展示压力曲线");
|
||||
await expect.poll(() => receipts.length).toBe(8);
|
||||
await expect(display.locator('[data-investigation-chart="chat-pressure"]')).toBeVisible();
|
||||
await page.getByRole("button", { name: "新建 Agent 对话", exact: true }).click();
|
||||
await expect(display).toContainText("当前没有展示结果");
|
||||
await expect(display.getByRole("combobox", { name: "切换展示动作" })).toBeVisible();
|
||||
await expect.poll(() => sourceSize("chat-presentation-highlights")).toBe(0);
|
||||
await expect.poll(() => sourceSize("preview-presentation-highlights")).toBe(1);
|
||||
await expect(page.locator('[data-investigation-chart="dev-pressure"]')).toBeVisible();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user