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:
@@ -7,7 +7,7 @@ test.beforeEach(async ({ page }) => {
|
||||
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||
await mockWorkbenchContext(page);
|
||||
await mockAgentApi(page);
|
||||
await page.route("**/api/v1/agent/chat/models", (route) => route.fulfill({
|
||||
await page.route("**/api/v1/models", (route) => route.fulfill({
|
||||
headers: { "Access-Control-Allow-Origin": "*" },
|
||||
json: {
|
||||
default_model: "test/fast",
|
||||
@@ -59,8 +59,8 @@ for (const width of [1440, 375]) {
|
||||
const trigger = page.locator('button[aria-label="权限批准模式"]');
|
||||
await trigger.click();
|
||||
await waitForMenuAnimations(page.getByRole("menu"));
|
||||
const request = page.getByRole("menuitem", { name: /工具权限逐次确认/ });
|
||||
const always = page.getByRole("menuitem", { name: /自动允许本轮权限请求/ });
|
||||
const request = page.getByRole("menuitem", { name: /需要审批的请求逐次确认/ });
|
||||
const always = page.getByRole("menuitem", { name: /自动批准本轮工具权限请求/ });
|
||||
for (const item of [request, always]) {
|
||||
await item.hover();
|
||||
await expectThemeColor(item, "background-color", "--action-selection-soft-hover");
|
||||
@@ -85,6 +85,81 @@ for (const width of [1440, 375]) {
|
||||
});
|
||||
}
|
||||
|
||||
test("sends the selected approval mode and can return to manual approval", async ({ page }) => {
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click();
|
||||
const trigger = page.getByRole("button", { name: "权限批准模式" });
|
||||
|
||||
for (const [label, mode] of [
|
||||
["自动批准本轮工具权限请求", "always"],
|
||||
["需要审批的请求逐次确认", "request"],
|
||||
] as const) {
|
||||
await expect(trigger).toBeEnabled();
|
||||
await trigger.click();
|
||||
await page.getByRole("menuitem", { name: new RegExp(label) }).click();
|
||||
await page.getByRole("textbox", { name: "询问供水问题,或描述需要处理的任务" }).fill(`验证权限模式 ${mode}`);
|
||||
const sent = page.waitForRequest((request) => request.method() === "POST" && request.url().endsWith("/api/v1/responses"));
|
||||
await page.getByRole("button", { name: "发送 Agent 指令" }).click();
|
||||
expect((await sent).postDataJSON().tjwater.approval_mode).toBe(mode);
|
||||
}
|
||||
await expect(trigger).toBeEnabled();
|
||||
});
|
||||
|
||||
test("replaces a removed model before sending and shows the model actually submitted", async ({ page }) => {
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click();
|
||||
const trigger = page.getByRole("button", { name: "选择 Agent 模型" });
|
||||
await expect(trigger).toHaveAccessibleDescription("当前模型:快速");
|
||||
await trigger.click();
|
||||
await page.getByRole("menuitem", { name: /深入分析和复杂任务处理/ }).click();
|
||||
await expect(trigger).toHaveAccessibleDescription("当前模型:专家");
|
||||
|
||||
// Simulate an Agent restart with a new catalog while this page stays open.
|
||||
await page.route("**/api/v1/models", (route) => route.fulfill({
|
||||
headers: { "Access-Control-Allow-Origin": "*" },
|
||||
json: {
|
||||
default_model: "waternetwork/gpt-6-luna",
|
||||
models: [{ id: "waternetwork/gpt-6-luna", label: "快速", description: "当前可用模型", icon: "bolt" }]
|
||||
}
|
||||
}));
|
||||
await page.getByRole("textbox", { name: "询问供水问题,或描述需要处理的任务" }).fill("检查更新后的快速模型");
|
||||
const sent = page.waitForRequest((request) => request.method() === "POST" && request.url().endsWith("/api/v1/responses"));
|
||||
await page.getByRole("button", { name: "发送 Agent 指令" }).click();
|
||||
expect((await sent).postDataJSON().model).toBe("waternetwork/gpt-6-luna");
|
||||
await expect(trigger).toHaveAccessibleDescription("当前模型:快速");
|
||||
});
|
||||
|
||||
test("keeps an explicitly selected model when it remains available", async ({ page }) => {
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click();
|
||||
const trigger = page.getByRole("button", { name: "选择 Agent 模型" });
|
||||
await expect(trigger).toHaveAccessibleDescription("当前模型:快速");
|
||||
await trigger.click();
|
||||
await page.getByRole("menuitem", { name: /深入分析和复杂任务处理/ }).click();
|
||||
await page.getByRole("textbox", { name: "询问供水问题,或描述需要处理的任务" }).fill("保留专家模型选择");
|
||||
const sent = page.waitForRequest((request) => request.method() === "POST" && request.url().endsWith("/api/v1/responses"));
|
||||
await page.getByRole("button", { name: "发送 Agent 指令" }).click();
|
||||
expect((await sent).postDataJSON().model).toBe("test/expert");
|
||||
await expect(trigger).toHaveAccessibleDescription("当前模型:专家");
|
||||
});
|
||||
|
||||
test("does not send a generation request when the refreshed catalog is empty", async ({ page }) => {
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click();
|
||||
await expect(page.getByRole("button", { name: "选择 Agent 模型" })).toHaveAccessibleDescription("当前模型:快速");
|
||||
await page.route("**/api/v1/models", (route) => route.fulfill({
|
||||
headers: { "Access-Control-Allow-Origin": "*" }, json: { default_model: "test/fast", models: [] }
|
||||
}));
|
||||
const requests: string[] = [];
|
||||
page.on("request", (request) => {
|
||||
if (request.method() === "POST" && request.url().endsWith("/api/v1/responses")) requests.push(request.url());
|
||||
});
|
||||
await page.getByRole("textbox", { name: "询问供水问题,或描述需要处理的任务" }).fill("检查空模型目录");
|
||||
await page.getByRole("button", { name: "发送 Agent 指令" }).click();
|
||||
await expect(page.getByText("Agent 后端当前没有可用模型,请检查模型配置。").first()).toBeVisible();
|
||||
expect(requests).toEqual([]);
|
||||
});
|
||||
|
||||
async function waitForMenuAnimations(menu: Locator) {
|
||||
await expect(menu).toBeVisible();
|
||||
await menu.evaluate((element) => Promise.all(
|
||||
|
||||
Reference in New Issue
Block a user