AkurAI Build
Menu

popagent

public

Latest change 908f9a5dd403d367842700d031df6148c37eeaad - Let follow-up planning target the finding's workspace and dedupe across workspaces by AkurAI Build

import { describe, expect, test } from "bun:test";
import { createFollowUps, followUpPlanSchema, followUpTitleOf, MAX_FOLLOW_UPS } from "./follow-ups";
import type { AgentSchedule, AgentTask } from "./api-types";

const schedule: AgentSchedule = {
  id: "s1", sessionId: null, workspaceId: "default", source: "user", name: "Daily report", prompt: "p",
  model: "policy/routing", maxAttempts: 3, cron: "0 10 * * *", timezone: "UTC", enabled: true, followUps: true,
  nextRunAt: null, lastRunAt: null, createdAt: "", updatedAt: "",
};
const task = { id: "t1", scheduleId: "s1", workspaceId: "default", output: "## Report\n- Reconcile the Project Index\n- Add mail telemetry" } as AgentTask;

describe("follow-up planning", () => {
  test("creates deduplicated linked tasks from planned items and announces counts", async () => {
    const created: Array<{ workspaceId: string; prompt: string; model: string; followUpOfTaskId: string }> = [];
    let seenContext: { workspaces: unknown; existingTitles: string[] } | undefined;
    const store = {
      recentFollowUpPrompts: async () => ["Follow-up: Reconcile the project index\n\nolder task"],
      createTask: async (input: typeof created[number]) => { created.push(input); return { id: `new-${created.length}`, prompt: input.prompt } as AgentTask; },
      workspaces: async () => [{ id: "default", name: "popagent" }, { id: "mon-1", name: "AkurAI-Monitor" }],
    };
    const result = await createFollowUps(task, schedule, store, async (_task, _schedule, context) => { seenContext = context; return { items: [
      { title: "Reconcile the Project Index", prompt: "Update popagent/project-index.md to the deployed revision with revision protection.", rationale: "Two pages disagree.", severity: "medium" },
      { title: "Add AkurAI-Mail telemetry collector", prompt: "Design a dns_metrics.rs-style collector for AkurAI-Mail journald lines; no deploy.", rationale: "Zero mail telemetry.", severity: "high", workspace: "AkurAI-Monitor" },
      { title: "Unknown workspace item", prompt: "Something bounded and reviewable inside the repository, with evidence.", rationale: "x", severity: "low", workspace: "nope" },
    ] }; });
    expect(seenContext?.existingTitles).toEqual(["Reconcile the project index"]);
    expect(result.planned).toBe(3);
    expect(result.skipped.map((item) => item.title)).toEqual(["Reconcile the Project Index"]);
    expect(result.created).toHaveLength(2);
    expect(created[0]).toMatchObject({ workspaceId: "mon-1", model: "policy/routing", followUpOfTaskId: "t1" });
    expect(created[1]).toMatchObject({ workspaceId: "default" });
    expect(created[0]!.prompt.startsWith("Follow-up: Add AkurAI-Mail telemetry collector")).toBe(true);
    expect(created[0]!.prompt).toContain("do not deploy");
    expect(followUpTitleOf(created[0]!.prompt)).toBe("add akurai mail telemetry collector");
  });

  test("does nothing when the schedule opted out, the run had no output, or the plan is empty", async () => {
    let planned = 0;
    const store = { recentFollowUpPrompts: async () => [], createTask: async () => { throw new Error("must not create"); }, workspaces: async () => [] };
    const plan = async () => { planned++; return { items: [] }; };
    expect((await createFollowUps(task, { ...schedule, followUps: false }, store, plan)).planned).toBe(0);
    expect((await createFollowUps({ ...task, output: "  " }, schedule, store, plan)).planned).toBe(0);
    expect(planned).toBe(0);
    expect((await createFollowUps(task, schedule, store, plan)).created).toEqual([]);
    expect(planned).toBe(1);
  });

  test("bounds the plan shape", () => {
    expect(followUpPlanSchema.safeParse({ items: Array.from({ length: MAX_FOLLOW_UPS + 1 }, () => ({ title: "x".repeat(10), prompt: "y".repeat(30), rationale: "z".repeat(5), severity: "low" })) }).success).toBe(false);
    expect(followUpPlanSchema.safeParse({ items: [{ title: "ok title", prompt: "y".repeat(30), rationale: "because", severity: "critical" }] }).success).toBe(false);
  });
});