2025-04-15 19:02:28 +08:00
|
|
|
|
/**
|
|
|
|
|
* planTask prompt 生成器
|
|
|
|
|
* 負責將模板和參數組合成最終的 prompt
|
|
|
|
|
*/
|
|
|
|
|
|
2025-04-26 19:58:52 +08:00
|
|
|
|
import {
|
|
|
|
|
loadPrompt,
|
|
|
|
|
generatePrompt,
|
|
|
|
|
loadPromptFromTemplate,
|
|
|
|
|
} from "../loader.js";
|
2025-04-19 03:02:44 +08:00
|
|
|
|
import { Task, TaskDependency } from "../../types/index.js";
|
2025-04-15 19:02:28 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* planTask prompt 參數介面
|
|
|
|
|
*/
|
|
|
|
|
export interface PlanTaskPromptParams {
|
|
|
|
|
description: string;
|
|
|
|
|
requirements?: string;
|
|
|
|
|
existingTasksReference?: boolean;
|
|
|
|
|
completedTasks?: Task[];
|
|
|
|
|
pendingTasks?: Task[];
|
|
|
|
|
memoryDir: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 獲取 planTask 的完整 prompt
|
|
|
|
|
* @param params prompt 參數
|
|
|
|
|
* @returns 生成的 prompt
|
|
|
|
|
*/
|
|
|
|
|
export function getPlanTaskPrompt(params: PlanTaskPromptParams): string {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
let tasksContent = "";
|
2025-04-15 19:02:28 +08:00
|
|
|
|
if (
|
|
|
|
|
params.existingTasksReference &&
|
|
|
|
|
params.completedTasks &&
|
|
|
|
|
params.pendingTasks
|
|
|
|
|
) {
|
|
|
|
|
const allTasks = [...params.completedTasks, ...params.pendingTasks];
|
|
|
|
|
// 如果存在任務,則添加相關資訊
|
|
|
|
|
if (allTasks.length > 0) {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
let completeTasksContent = "no completed tasks";
|
2025-04-15 19:02:28 +08:00
|
|
|
|
|
|
|
|
|
// 處理已完成任務
|
|
|
|
|
if (params.completedTasks.length > 0) {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
completeTasksContent = "";
|
2025-04-15 19:02:28 +08:00
|
|
|
|
// 最多顯示10個已完成任務,避免提示詞過長
|
|
|
|
|
const tasksToShow =
|
|
|
|
|
params.completedTasks.length > 10
|
|
|
|
|
? params.completedTasks.slice(0, 10)
|
|
|
|
|
: params.completedTasks;
|
|
|
|
|
|
|
|
|
|
tasksToShow.forEach((task, index) => {
|
|
|
|
|
// 產生完成時間資訊 (如果有)
|
|
|
|
|
const completedTimeText = task.completedAt
|
2025-04-26 19:58:52 +08:00
|
|
|
|
? ` - completedAt:${task.completedAt.toLocaleString()}\n`
|
2025-04-15 19:02:28 +08:00
|
|
|
|
: "";
|
|
|
|
|
|
2025-04-26 19:58:52 +08:00
|
|
|
|
completeTasksContent += `{index}. **${task.name}** (ID: \`${
|
|
|
|
|
task.id
|
|
|
|
|
}\`)\n - description:${
|
|
|
|
|
task.description.length > 100
|
|
|
|
|
? task.description.substring(0, 100) + "..."
|
|
|
|
|
: task.description
|
|
|
|
|
}\n${completedTimeText}`;
|
2025-04-15 19:02:28 +08:00
|
|
|
|
// 如果不是最後一個任務,添加換行
|
|
|
|
|
if (index < tasksToShow.length - 1) {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
completeTasksContent += "\n\n";
|
2025-04-15 19:02:28 +08:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 如果有更多任務,顯示提示
|
|
|
|
|
if (params.completedTasks.length > 10) {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
completeTasksContent += `\n\n*(僅顯示前10個,共 ${params.completedTasks.length} 個)*\n`;
|
2025-04-15 19:02:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-26 19:58:52 +08:00
|
|
|
|
let unfinishedTasksContent = "no pending tasks";
|
2025-04-15 19:02:28 +08:00
|
|
|
|
// 處理未完成任務
|
|
|
|
|
if (params.pendingTasks && params.pendingTasks.length > 0) {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
unfinishedTasksContent = "";
|
2025-04-15 19:02:28 +08:00
|
|
|
|
|
|
|
|
|
params.pendingTasks.forEach((task, index) => {
|
|
|
|
|
const dependenciesText =
|
|
|
|
|
task.dependencies && task.dependencies.length > 0
|
2025-04-26 19:58:52 +08:00
|
|
|
|
? ` - dependence:${task.dependencies
|
2025-04-15 19:02:28 +08:00
|
|
|
|
.map((dep: TaskDependency) => `\`${dep.taskId}\``)
|
|
|
|
|
.join(", ")}\n`
|
|
|
|
|
: "";
|
|
|
|
|
|
2025-04-26 19:58:52 +08:00
|
|
|
|
unfinishedTasksContent += `${index + 1}. **${task.name}** (ID: \`${
|
|
|
|
|
task.id
|
|
|
|
|
}\`)\n - description:${
|
|
|
|
|
task.description.length > 150
|
|
|
|
|
? task.description.substring(0, 150) + "..."
|
|
|
|
|
: task.description
|
|
|
|
|
}\n - status:${task.status}\n${dependenciesText}`;
|
2025-04-15 19:02:28 +08:00
|
|
|
|
|
|
|
|
|
// 如果不是最後一個任務,添加換行
|
|
|
|
|
if (index < (params.pendingTasks?.length ?? 0) - 1) {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
unfinishedTasksContent += "\n\n";
|
2025-04-15 19:02:28 +08:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-26 19:58:52 +08:00
|
|
|
|
const tasksTemplate = loadPromptFromTemplate("planTask/tasks.md");
|
|
|
|
|
tasksContent = generatePrompt(tasksTemplate, {
|
|
|
|
|
completedTasks: completeTasksContent,
|
|
|
|
|
unfinishedTasks: unfinishedTasksContent,
|
|
|
|
|
});
|
2025-04-15 19:02:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-26 19:58:52 +08:00
|
|
|
|
let thoughtTemplate = "";
|
2025-04-15 20:50:29 +08:00
|
|
|
|
if (process.env.ENABLE_THOUGHT_CHAIN !== "false") {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
thoughtTemplate = loadPromptFromTemplate("planTask/hasThought.md");
|
2025-04-15 20:50:29 +08:00
|
|
|
|
} else {
|
2025-04-26 19:58:52 +08:00
|
|
|
|
thoughtTemplate = loadPromptFromTemplate("planTask/noThought.md");
|
2025-04-15 20:50:29 +08:00
|
|
|
|
}
|
2025-04-26 19:58:52 +08:00
|
|
|
|
const indexTemplate = loadPromptFromTemplate("planTask/index.md");
|
|
|
|
|
let prompt = generatePrompt(indexTemplate, {
|
|
|
|
|
description: params.description,
|
|
|
|
|
requirements: params.requirements || "No requirements",
|
|
|
|
|
tasksTemplate: tasksContent,
|
2025-05-10 19:15:29 +08:00
|
|
|
|
rulesPath: "shrimp-rules.md",
|
2025-04-26 19:58:52 +08:00
|
|
|
|
memoryDir: params.memoryDir,
|
|
|
|
|
thoughtTemplate: thoughtTemplate,
|
|
|
|
|
});
|
2025-04-15 19:02:28 +08:00
|
|
|
|
|
|
|
|
|
// 載入可能的自定義 prompt
|
2025-04-26 19:58:52 +08:00
|
|
|
|
return loadPrompt(prompt, "PLAN_TASK");
|
2025-04-15 19:02:28 +08:00
|
|
|
|
}
|