diff --git a/server/src/__tests__/task-watchdogs-classifier.test.ts b/server/src/__tests__/task-watchdogs-classifier.test.ts index 16ef800c088..71865c75dfe 100644 --- a/server/src/__tests__/task-watchdogs-classifier.test.ts +++ b/server/src/__tests__/task-watchdogs-classifier.test.ts @@ -1,8 +1,6 @@ -import { describe, expect, it, vi } from "vitest"; +import { describe, expect, it } from "vitest"; import { classifyTaskWatchdogSubtree, type TaskWatchdogClassifierIssue } from "../services/task-watchdogs.ts"; -import { createIncompleteTaskWatchdogScanReporter } from "../services/task-watchdog-diagnostics.ts"; - const companyId = "company-1"; const sourceId = "source-1"; const childId = "child-1"; @@ -37,39 +35,6 @@ function classify(overrides: Partial { - it("reports an unchanged incomplete scan once across startup and a day of periodic ticks", () => { - const warn = vi.fn(); - const report = createIncompleteTaskWatchdogScanReporter(warn); - report({ incomplete: 2, incompleteIssueIds: [sourceId, childId] }, "startup"); - for (let tick = 0; tick < 2880; tick += 1) { - report({ incomplete: 2, incompleteIssueIds: [childId, sourceId] }, "periodic"); - } - expect(warn).toHaveBeenCalledTimes(1); - expect(warn).toHaveBeenCalledWith( - { incomplete: 2, newIncompleteIssueIds: [sourceId, childId] }, - "startup task-watchdog reconciliation found incomplete subtree scans", - ); - }); - - it("reports new incomplete issues and reports a resolved issue if it becomes incomplete again", () => { - const warn = vi.fn(); - const report = createIncompleteTaskWatchdogScanReporter(warn); - report({ incomplete: 1, incompleteIssueIds: [sourceId] }, "startup"); - report({ incomplete: 2, incompleteIssueIds: [sourceId, childId] }, "periodic"); - expect(warn).toHaveBeenLastCalledWith( - { incomplete: 2, newIncompleteIssueIds: [childId] }, - "periodic task-watchdog reconciliation found incomplete subtree scans", - ); - report({ incomplete: 0, incompleteIssueIds: [] }, "periodic"); - expect(warn).toHaveBeenCalledTimes(2); - report({ incomplete: 1, incompleteIssueIds: [sourceId] }, "periodic"); - expect(warn).toHaveBeenCalledTimes(3); - expect(warn).toHaveBeenLastCalledWith( - { incomplete: 1, newIncompleteIssueIds: [sourceId] }, - "periodic task-watchdog reconciliation found incomplete subtree scans", - ); - }); - it("does not produce a stopped fingerprint from an incomplete scan", () => { const result = classify({ subtreeIncomplete: true }); expect(result.state).toBe("incomplete"); diff --git a/server/src/services/task-watchdog-diagnostics.ts b/server/src/services/task-watchdog-diagnostics.ts deleted file mode 100644 index ea08eebe2b4..00000000000 --- a/server/src/services/task-watchdog-diagnostics.ts +++ /dev/null @@ -1,16 +0,0 @@ -export function createIncompleteTaskWatchdogScanReporter( - warn: (details: { incomplete: number; newIncompleteIssueIds: string[] }, message: string) => void, -) { - let previousIncompleteIssueIds = new Set(); - return (result: { incomplete: number; incompleteIssueIds: string[] }, phase: "startup" | "periodic") => { - const currentIssueIds = new Set(result.incompleteIssueIds); - const newIncompleteIssueIds = [...currentIssueIds].filter((id) => !previousIncompleteIssueIds.has(id)); - previousIncompleteIssueIds = currentIssueIds; - if (newIncompleteIssueIds.length === 0) return; - warn( - { incomplete: result.incomplete, newIncompleteIssueIds }, - `${phase} task-watchdog reconciliation found incomplete subtree scans`, - ); - }; -} - diff --git a/tests/e2e/agent-chat-projects.spec.ts b/tests/e2e/agent-chat-projects.spec.ts index 994df38746c..89ec94ca54c 100644 --- a/tests/e2e/agent-chat-projects.spec.ts +++ b/tests/e2e/agent-chat-projects.spec.ts @@ -459,12 +459,15 @@ test("plan approval hands the preserved revision to an assigned project task", a { timeout: 60_000 }, ) .toBe(1); + // Task completion is delivered back to the chat as another real turn. + await idle(request, f.chatPath, 3); const task = ( await json(await request.get(`/api/companies/${f.company.id}/issues`)) )[0]; expect(task.parentId).toBeNull(); expect(task.projectId).toBeTruthy(); expect(task.assigneeAgentId).toBe(f.agent.id); + await expect(page.getByText(`Delegated work completed: ${task.identifier}`, { exact: true })).toBeVisible(); const plan = await json( await request.get(`/api/issues/${task.id}/documents/plan`), ); diff --git a/tests/e2e/fixtures/agent-chat.mjs b/tests/e2e/fixtures/agent-chat.mjs index 2a66bdd3111..d85ab355679 100644 --- a/tests/e2e/fixtures/agent-chat.mjs +++ b/tests/e2e/fixtures/agent-chat.mjs @@ -36,6 +36,10 @@ if (!task.conversationAgentId) { }); process.exit(0); } +if (ctx.wakeReason === "chat_task_completed") { + await comment(`Delegated work completed: ${ctx.chatCompletionUpdates.map((update) => update.identifier).join(", ")}`); + process.exit(0); +} const comments = await api(`/issues/${task.id}/comments?order=asc`); const current = comments.find((c) => c.id === ctx.wakeCommentId) ??