AkurAI Build
Menu

popagent

public

Latest change b1ce7780419661fdbaa419ac388e20658c4f7caf - Release 1.0.50: task list slimming, remediation auto-requeue, research handoff synthesis 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("Checking the repository contract")).toBeLessThan(html.indexOf("Older activity"));
  });

  test("shows delegated specialist work distinctly from ordinary tool calls", () => {
    const html = renderToStaticMarkup(<TaskTerminalDialog
      task={task("running", {
        activity: [{
          turnId: "turn-1",
          runId: "run-1",
          agentId: "orchistrator",
          agentName: "Orchistrator",
          iteration: 1,
          maxIterations: 128,
          isFinal: false,
          finishReason: "tool-calls",
          text: "",
          tools: ["agent-communication"],
          toolCalls: [{
            id: "call-1",
            name: "agent-communication",
            args: { op: "send", to: "staff-thordis", message: "Prepare the founder report" },
            result: { to: "staff-thordis", outcome: "woken" },
            status: "complete",
          }],
        }],
      })}
      stepLimit={128}
      onClose={() => {}}
    />);

    expect(html).toContain("Delegated to");
    expect(html).toContain("staff-thordis");
    expect(html).toContain("woken");
    expect(html).not.toContain(">agent-communication<");
  });
});