CoDEVX / lib /automation-agent.ts
Tiger's Macbook Air
Build agentic PM demo app
3f76ff4
import type { ChatResponse } from "./board-actions";
import { getWorkPackageSpec } from "./work-package-specs";
import type { WorkPackage, WorkPackageOutput } from "./work-package-types";
export const REAL_AUTOMATION_DISCLAIMER =
"This output was generated by the user-configured LLM. No real engineering toolchain, certification authority, patent database, hardware test bench, or external enterprise system was executed.";
function nowIso() {
return new Date().toISOString();
}
function newId(prefix: string) {
return `${prefix}-${crypto.randomUUID()}`;
}
function productBriefFromBoard(workPackages: WorkPackage[]) {
return workPackages
.flatMap((workPackage) => workPackage.inputFiles)
.find((input) => input.startsWith("Product brief: "))
?.replace(/^Product brief:\s*/, "");
}
function completedTasks(workPackage: WorkPackage) {
return workPackage.tasks.map((task) => ({
...task,
status: "done" as const,
}));
}
function previousOutputsSummary(workPackages: WorkPackage[], currentId: string) {
return workPackages
.filter((workPackage) => workPackage.id !== currentId)
.flatMap((workPackage) =>
workPackage.outputs.map((output) =>
[
`Package: ${workPackage.title}`,
`Output: ${output.title}`,
output.content.slice(0, 500),
].join("\n"),
),
)
.slice(-6)
.join("\n\n");
}
function buildOutputTitle(workPackage: WorkPackage, instruction: string) {
return instruction
? `${workPackage.shortName} Automation - ${instruction}`
: `${workPackage.shortName} Automation Output`;
}
export function buildExecutionPrompt(args: {
workPackage: WorkPackage;
workPackages: WorkPackage[];
productIdea?: string;
instruction?: string;
}) {
const { workPackage, workPackages, instruction } = args;
const spec = getWorkPackageSpec(workPackage);
const productIdea =
args.productIdea?.trim() || productBriefFromBoard(workPackages) || "";
const priorContext = previousOutputsSummary(workPackages, workPackage.id);
return [
`You are completing the work package "${workPackage.title}" (${workPackage.shortName}).`,
productIdea ? `Product idea: ${productIdea}` : "",
`Objective: ${workPackage.objective}`,
workPackage.inputFiles.length
? `Expected inputs: ${workPackage.inputFiles.join(", ")}`
: "",
workPackage.outputFiles.length
? `Expected outputs: ${workPackage.outputFiles.join(", ")}`
: "",
workPackage.coreSections.length
? `Core sections: ${workPackage.coreSections.join(", ")}`
: "",
workPackage.deliverables?.length
? `Deliverables: ${workPackage.deliverables
.map((item) => `${item.name} (${item.required ? "required" : "optional"})`)
.join(", ")}`
: "",
spec?.askHint ? `Planning hint: ${spec.askHint}` : "",
instruction ? `User instruction: ${instruction}` : "",
priorContext
? `Recent outputs from other packages for cross-reference:\n\n${priorContext}`
: "",
"Return only the actual artifact content in markdown.",
"Be concrete and package-specific.",
"Do not mention being an AI, do not return JSON, and do not mention the disclaimer.",
]
.filter(Boolean)
.join("\n\n");
}
export function buildRealExecutionResponse(args: {
workPackage: WorkPackage;
generatedContent: string;
instruction?: string;
productIdea?: string;
}): ChatResponse {
const { workPackage, generatedContent, instruction } = args;
const spec = getWorkPackageSpec(workPackage);
const output: WorkPackageOutput = {
id: newId("out"),
title: buildOutputTitle(workPackage, instruction?.trim() || ""),
type: spec?.outputType ?? "text",
content: generatedContent,
createdAt: nowIso(),
sourceTaskId: workPackage.tasks[0]?.id ?? null,
executionMode: "real",
disclaimer: REAL_AUTOMATION_DISCLAIMER,
};
return {
assistantMessage: `${workPackage.shortName} automation completed with the configured model.`,
boardAction: {
type: "update",
workPackageId: workPackage.id,
fields: {
status: "done",
tasks: completedTasks(workPackage),
outputs: [...workPackage.outputs, output],
},
},
};
}
export function buildAutomationInstruction(workPackage: WorkPackage) {
return `Generate all expected outputs for ${workPackage.title} and complete this work package.`;
}