feat(FN-3029): add research settings, AgentDetailView markdown viewer, and
This merge brings several enhancements across the dashboard and engine. Research settings are now fully integrated into the settings modal and exported for alias builds, including a new schema and dedicated resolver. The AgentDetailView receives a heartbeat markdown viewer modal and expanded styling Fusion-Task-Id: FN-3029
This commit is contained in:
@@ -4172,6 +4172,55 @@ describe("TaskExecutor global pause behavior", () => {
|
||||
expect(store.moveTask).not.toHaveBeenCalledWith("FN-001", "todo");
|
||||
});
|
||||
|
||||
it("promotes todo tasks to in-progress when fn_task_done is called while paused", async () => {
|
||||
const store = createMockStore();
|
||||
let capturedCustomTools: any[] = [];
|
||||
|
||||
const todoTask = {
|
||||
id: "FN-001",
|
||||
title: "Test",
|
||||
description: "T",
|
||||
prompt: "# test\n## Steps\n### Step 0: Preflight\n- [ ] check",
|
||||
column: "todo",
|
||||
paused: true,
|
||||
dependencies: [],
|
||||
steps: [{ name: "Step 1", status: "pending" }],
|
||||
currentStep: 0,
|
||||
log: [],
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
store.getTask.mockResolvedValue(todoTask);
|
||||
store.moveTask.mockImplementation(async (_id: string, to: string) => ({ ...todoTask, column: to, paused: undefined }));
|
||||
|
||||
mockedCreateFnAgent.mockImplementation((async (opts: any) => {
|
||||
capturedCustomTools = opts.customTools || [];
|
||||
return {
|
||||
session: {
|
||||
prompt: vi.fn().mockImplementation(async () => {
|
||||
const taskDoneTool = capturedCustomTools.find((tool: any) => tool.name === "fn_task_done");
|
||||
if (taskDoneTool) {
|
||||
await taskDoneTool.execute("call-1", { summary: "done" });
|
||||
}
|
||||
}),
|
||||
dispose: vi.fn(),
|
||||
},
|
||||
};
|
||||
}) as any);
|
||||
|
||||
const executor = new TaskExecutor(store, "/tmp/test");
|
||||
await executor.execute(todoTask as any);
|
||||
|
||||
expect(store.updateTask).toHaveBeenCalledWith("FN-001", { paused: false, status: null });
|
||||
expect(store.moveTask).toHaveBeenCalledWith("FN-001", "in-progress");
|
||||
expect(store.moveTask).toHaveBeenCalledWith("FN-001", "in-review");
|
||||
expect(store.logEntry).toHaveBeenCalledWith(
|
||||
"FN-001",
|
||||
expect.stringContaining("fn_task_done called while task was in todo"),
|
||||
);
|
||||
});
|
||||
|
||||
it("takes no action when globalPause remains false", async () => {
|
||||
const store = createMockStore();
|
||||
const disposeFn = vi.fn();
|
||||
|
||||
@@ -3413,8 +3413,24 @@ export class TaskExecutor {
|
||||
if (params.summary) {
|
||||
await store.updateTask(taskId, { summary: params.summary });
|
||||
}
|
||||
await store.updateTask(taskId, { paused: false, status: null });
|
||||
await store.logEntry(taskId, "Task marked done by agent");
|
||||
this.scheduleCompletedTaskWatchdog(taskId, "fn_task_done");
|
||||
|
||||
const latestTask = await store.getTask(taskId);
|
||||
let latestColumn = latestTask.column;
|
||||
if (latestColumn === "todo") {
|
||||
await store.logEntry(
|
||||
taskId,
|
||||
"fn_task_done called while task was in todo — promoting to in-progress before completion handoff",
|
||||
);
|
||||
await store.moveTask(taskId, "in-progress");
|
||||
latestColumn = "in-progress";
|
||||
}
|
||||
|
||||
if (latestColumn === "in-progress") {
|
||||
this.scheduleCompletedTaskWatchdog(taskId, "fn_task_done");
|
||||
}
|
||||
|
||||
const successMessage = params.summary
|
||||
? "Task marked complete with summary. All steps done. Moving to in-review."
|
||||
: "Task marked complete. All steps done. Moving to in-review.";
|
||||
|
||||
Reference in New Issue
Block a user