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.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { fireEvent, render, screen, waitFor, within } from "@testing-library/react";
|
||||
import type { ComponentProps } from "react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { type AgentExecutionPlan } from "@/features/agent";
|
||||
@@ -130,6 +130,25 @@ function taskPanel(task: OperationalTask, overrides: Partial<ComponentProps<type
|
||||
return { ...props, rerender };
|
||||
}
|
||||
|
||||
it("references the selected report round instead of the latest task round, including legacy reports", () => {
|
||||
const task = { ...taskBase, execution_generation: 2 };
|
||||
const { rerender, ...props } = taskPanel(task);
|
||||
const button = screen.getByRole("button", { name: "Agent 协作" });
|
||||
expect(button).toHaveAttribute("title", "打开调查协作对话,引用此任务,不会直接发送。");
|
||||
fireEvent.click(button);
|
||||
expect(props.onContinue).toHaveBeenLastCalledWith({
|
||||
context: { report_revision: task.latest_report!.revision },
|
||||
reportGeneration: task.latest_report!.execution_generation
|
||||
});
|
||||
rerender(<AgentExecutionPlanPanel {...props} task={{ ...task,
|
||||
latest_report: { ...task.latest_report!, execution_generation: null }
|
||||
}} />);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Agent 协作" }));
|
||||
expect(props.onContinue).toHaveBeenLastCalledWith({
|
||||
context: { report_revision: task.latest_report!.revision }, reportGeneration: null
|
||||
});
|
||||
});
|
||||
|
||||
describe("operational task approval and evidence", () => {
|
||||
it("shows the selected v2 route first and keeps unchosen work available", () => {
|
||||
const node = (id: string, title: string, status: "completed" | "waiting" | "skipped") => ({
|
||||
@@ -294,7 +313,8 @@ describe("operational task approval and evidence", () => {
|
||||
onContinue={vi.fn()} onDecision={vi.fn()} onExecute={vi.fn()} onReconcile={vi.fn()}
|
||||
onRefresh={vi.fn()} onLoadEvidenceSnapshot={vi.fn()}
|
||||
/>);
|
||||
fireEvent.click(screen.getByRole("button", { name: "查看新报告" }));
|
||||
// Live reading follows published reports without requiring an update click.
|
||||
expect(screen.queryByRole("button", { name: "查看新报告" })).not.toBeInTheDocument();
|
||||
expect(screen.getByText(/正在阅读:历史报告/)).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -347,11 +367,24 @@ describe("operational task approval and evidence", () => {
|
||||
task={{ ...currentPlanTask, latest_plan: { ...latestPlan, execution_generation: null } }}
|
||||
{...props}
|
||||
/>);
|
||||
// An unassigned historical plan cannot supply a numbered report's diagram.
|
||||
expect(screen.queryByRole("heading", { name: "调查脉络" })).not.toBeInTheDocument();
|
||||
expect(within(screen.getByRole("region", { name: "任务报告" }))
|
||||
.getByText(taskBase.latest_report!.report.current_conclusion, { exact: true })).toBeVisible();
|
||||
|
||||
rerender(<AgentExecutionPlanPanel
|
||||
task={{ ...currentPlanTask,
|
||||
latest_plan: { ...latestPlan, execution_generation: null },
|
||||
latest_report: { ...taskBase.latest_report!, execution_generation: null }
|
||||
}}
|
||||
{...props}
|
||||
/>);
|
||||
// The legacy relationship remains readable when both records lack a round.
|
||||
expect(screen.getByRole("heading", { name: "调查脉络" })).toBeVisible();
|
||||
expect(screen.queryByText(/generation|第\s*\d+\s*代/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows exact payload and evidence metadata to a viewer without action controls", () => {
|
||||
it("shows exact payload and evidence metadata to a viewer without action controls", async () => {
|
||||
taskPanel(taskBase);
|
||||
expect(screen.getByText("工单标题")).toBeVisible();
|
||||
expect(screen.getByText("位置")).toBeVisible();
|
||||
@@ -363,9 +396,10 @@ describe("operational task approval and evidence", () => {
|
||||
expect(screen.getByText(/当前账号仅可查看/)).toBeVisible();
|
||||
expect(screen.queryByText(/operational_action\.work_order\.approve/)).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole("button", { name: "批准创建预约工单" })).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByLabelText("主要依据").querySelector("summary")!);
|
||||
expect(screen.getByText("SCADA 水质监测")).toBeVisible();
|
||||
expect(screen.getByText("系统数据")).toBeVisible();
|
||||
fireEvent.click(screen.getByRole("button", { name: "展开主要依据" }));
|
||||
fireEvent.click(screen.getByRole("dialog", { name: "主要依据" }).querySelector("summary")!);
|
||||
await waitFor(() => expect(within(screen.getByRole("dialog", { name: "主要依据" })).getByText("SCADA 水质监测")).toBeVisible());
|
||||
expect(within(screen.getByRole("dialog", { name: "主要依据" })).getByText("系统数据")).toBeVisible();
|
||||
});
|
||||
|
||||
it("keeps pending state after a decision network error", async () => {
|
||||
@@ -449,7 +483,7 @@ describe("operational task approval and evidence", () => {
|
||||
actions: [completedAction]
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByText("任务时间线"));
|
||||
fireEvent.click(screen.getByRole("button", { name: "展开任务时间线" }));
|
||||
const items = [...screen.getByLabelText("任务时间线记录").querySelectorAll("li")];
|
||||
expect(items.map((item) => item.textContent)).toEqual([
|
||||
expect.stringContaining("预约工单已创建,等待现场处理"),
|
||||
|
||||
Reference in New Issue
Block a user