Menu
popagent
publicLatest change fadf21d1cd584745f6f92eaa60509e0bef19d242 - fix task orchestration and compact overview cards by AkurAI Build
import { describe, expect, test } from "bun:test";
import { renderToStaticMarkup } from "react-dom/server";
import type { AgentTask } from "../api-types";
import { formatTaskTimestamp, TaskKanbanBoard, TaskTerminalDialog, taskKanbanLane } from "./TaskKanban";
function task(status: AgentTask["status"], overrides: Partial<AgentTask> = {}): AgentTask {
return {
id: `${status}-task`,
sessionId: null,
scheduleId: null,
source: "user",
workspaceId: "mail",
prompt: "Add client autoconfiguration\nKeep secure defaults.",
model: "cx/gpt-5.6-sol",
status,
output: null,
error: null,
stepsCompleted: 0,
progress: null,
recoveryCount: 0,
attemptCount: 1,
maxAttempts: 3,
nextAttemptAt: null,
lastErrorClass: null,
deadLetteredAt: null,
createdAt: "2026-08-14T18:16:51.000Z",
startedAt: null,
completedAt: null,
...overrides,
};
}
describe("task Kanban", () => {
test("groups every runtime status into an operator-facing lane", () => {
expect(taskKanbanLane("queued")).toBe("queued");
expect(taskKanbanLane("running")).toBe("active");
expect(taskKanbanLane("cancelling")).toBe("active");
expect(taskKanbanLane("completed")).toBe("done");
expect(taskKanbanLane("failed")).toBe("attention");
expect(taskKanbanLane("cancelled")).toBe("attention");
expect(taskKanbanLane("dead-letter")).toBe("attention");
});
test("formats recent task activity as relative time", () => {
expect(formatTaskTimestamp("2026-08-16T12:55:00.000Z", new Date("2026-08-16T13:00:00.000Z"))).toBe("5 minutes ago");
});
test("renders lane counts, live progress, blockers, and collapsible evidence", () => {
const html = renderToStaticMarkup(<TaskKanbanBoard
tasks={[
task("queued"),
task("running", { source: "build-maintenance", stepsCompleted: 7, progress: "Build Maintainer: checking CI" }),
task("completed", { output: "Checks passed\nCommit abc123" }),
task("failed", { error: "Missing DNS access", lastErrorClass: "permission" }),
]}
stepLimit={24}
workspaceNames={{ mail: "AkurAI-Mail" }}
onCancel={() => {}}
onRemove={() => {}}
/>);
expect(html).toContain("Queued");
expect(html).toContain("In progress");
expect(html).toContain("Done");
expect(html).toContain("Needs attention");
expect(html).toContain("Build Maintainer is working");
expect(html).not.toContain("Build Maintainer: checking CI");
expect(html).not.toContain("7 of 24 steps");
expect(html).toContain("Missing DNS access");
expect(html).toContain("AkurAI-Mail");
expect(html).toContain('aria-label="Open task run: Add client autoconfiguration"');
expect(html).toContain('aria-label="Task actions"');
expect(html).toContain("Build maintenance");
expect(html).toContain("Remove from board");
expect(html).toContain("max-h-[32rem]");
expect(html).toContain("overflow-y-auto");
});
test("renders a chat-style task transcript with prompts, thinking, tool details, and output", () => {
const html = renderToStaticMarkup(<TaskTerminalDialog
task={task("running", {
progress: "Researcher: Using webSearch",
activity: [{
turnId: "turn-1",
runId: "run-1",
agentId: "orchistrator",
agentName: "Orchistrator",
iteration: 1,
maxIterations: 128,
isFinal: false,
finishReason: "tool-calls",
text: "Older activity",
tools: ["read"],
toolCalls: [{
id: "call-1",
name: "read",
args: { path: "AGENTS.md" },
result: { content: "Repository rules" },
status: "complete",
}],
}, {
turnId: "turn-1",
runId: "run-2",
agentId: "researcher",
agentName: "Researcher",
iteration: 2,
maxIterations: 12,
isFinal: false,
finishReason: "tool-calls",
text: "Checking the repository contract",
tools: ["skill_search", "read"],
toolCalls: [{
id: "call-2",
name: "skill_search",
args: { query: "deployment" },
error: "catalog unavailable",
status: "error",
}],
}],
})}
stepLimit={128}
onClose={() => {}}
/>);
expect(html).toContain("Task run");
expect(html).toContain("Add client autoconfiguration");
expect(html).toContain("You");
expect(html).toContain("Orchistrator");
expect(html).toContain("Researcher");
expect(html).toContain("thinking");
expect(html).toContain("skill_search");
expect(html).toContain("AGENTS.md");
expect(html).toContain("Repository rules");
expect(html).toContain("catalog unavailable");
expect(html).toContain("Checking the repository contract");
expect(html).toContain("0 of 128 steps");
expect(html.indexOf("Older activity")).toBeLessThan(html.indexOf("Checking the repository contract"));
});
});