121 lines
4.1 KiB
TypeScript
121 lines
4.1 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { cronUnauthorizedResponse, isCronRequestAuthorized } from "@/lib/cron-auth";
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
export async function POST(request: Request) {
|
|
if (!isCronRequestAuthorized(request)) {
|
|
return cronUnauthorizedResponse("A2A Swarm");
|
|
}
|
|
|
|
console.log("[A2A Swarm] Starting task decomposition scan...");
|
|
|
|
try {
|
|
// 1. Find all OPEN high-value EPIC tasks that haven't been decomposed yet
|
|
const epicTasks = await prisma.task.findMany({
|
|
where: {
|
|
status: "OPEN",
|
|
difficulty: "EPIC",
|
|
}
|
|
});
|
|
|
|
if (epicTasks.length === 0) {
|
|
console.log('[A2A Swarm] No EPIC tasks found to decompose.');
|
|
return NextResponse.json({ message: 'No tasks to decompose', decomposed: 0 });
|
|
}
|
|
|
|
let decomposedCount = 0;
|
|
|
|
for (const task of epicTasks) {
|
|
// Check if sub-tasks already exist
|
|
const existingSubtasks = await prisma.task.count({
|
|
where: { parent_task_id: task.id }
|
|
});
|
|
|
|
if (existingSubtasks > 0) {
|
|
console.log(`[A2A Swarm] Task ${task.id} already decomposed into ${existingSubtasks} subtasks.`);
|
|
continue;
|
|
}
|
|
|
|
console.log(`[A2A Swarm] Decomposing EPIC task ${task.id}: ${task.title}`);
|
|
|
|
// We divide the reward. E.g., 40% Frontend, 40% Backend, 20% QA
|
|
const totalReward = task.reward_amount;
|
|
const r1 = Math.floor(totalReward * 0.4);
|
|
const r2 = Math.floor(totalReward * 0.4);
|
|
const r3 = totalReward - r1 - r2;
|
|
|
|
// 2. Create sub-tasks
|
|
await prisma.$transaction(async (tx) => {
|
|
// Subtask 1: Frontend
|
|
await tx.task.create({
|
|
data: {
|
|
title: `[Frontend] ${task.title}`,
|
|
description: `Frontend implementation for ${task.title}. Refer to parent task.`,
|
|
status: "OPEN",
|
|
difficulty: "COMPONENT",
|
|
scope_clarity_score: task.scope_clarity_score,
|
|
reward_amount: r1,
|
|
reward_currency: task.reward_currency,
|
|
acceptance_criteria: task.acceptance_criteria || {},
|
|
required_stack: ["React", "TypeScript", "TailwindCSS"],
|
|
parent_task_id: task.id
|
|
}
|
|
});
|
|
|
|
// Subtask 2: Backend
|
|
await tx.task.create({
|
|
data: {
|
|
title: `[Backend] ${task.title}`,
|
|
description: `Backend implementation for ${task.title}. Refer to parent task.`,
|
|
status: "OPEN",
|
|
difficulty: "COMPONENT",
|
|
scope_clarity_score: task.scope_clarity_score,
|
|
reward_amount: r2,
|
|
reward_currency: task.reward_currency,
|
|
acceptance_criteria: task.acceptance_criteria || {},
|
|
required_stack: ["Node.js", "Express", "PostgreSQL"],
|
|
parent_task_id: task.id
|
|
}
|
|
});
|
|
|
|
// Subtask 3: QA
|
|
await tx.task.create({
|
|
data: {
|
|
title: `[QA/Audit] ${task.title}`,
|
|
description: `Quality Assurance and Auditing for ${task.title}.`,
|
|
status: "OPEN",
|
|
difficulty: "COMPONENT",
|
|
scope_clarity_score: Math.max(1.0, task.scope_clarity_score + 0.1),
|
|
reward_amount: r3,
|
|
reward_currency: task.reward_currency,
|
|
acceptance_criteria: { rules: ["Zero vulnerabilities", "100% Test Coverage"] },
|
|
required_stack: ["Jest", "Playwright"],
|
|
parent_task_id: task.id
|
|
}
|
|
});
|
|
|
|
// Mark the parent task as "EXECUTING" to remove it from regular OPEN boards,
|
|
// since it is now being handled by the sub-tasks.
|
|
await tx.task.update({
|
|
where: { id: task.id },
|
|
data: { status: "EXECUTING" }
|
|
});
|
|
});
|
|
|
|
console.log(`[A2A Swarm] Successfully decomposed Task ${task.id} into 3 subtasks.`);
|
|
decomposedCount++;
|
|
}
|
|
|
|
return NextResponse.json({
|
|
message: "Swarm decomposition completed",
|
|
decomposed: decomposedCount
|
|
});
|
|
|
|
} catch (error: unknown) {
|
|
console.error("[A2A Swarm] Error during decomposition:", error);
|
|
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
|
|
}
|
|
}
|