diff --git a/agents/zhuyuan-dev-agent/modules/plan-expander.js b/agents/zhuyuan-dev-agent/modules/plan-expander.js index c76d83b..c2ada37 100644 --- a/agents/zhuyuan-dev-agent/modules/plan-expander.js +++ b/agents/zhuyuan-dev-agent/modules/plan-expander.js @@ -1,77 +1,99 @@ -// ═══════════════════════════════════════ -// 铸渊开发Agent · 任务补全引擎 +// HLDP-ZY://agents/zhuyuan-dev-agent/modules/plan-expander.js +// @guardian: ICE-GL-ZY001 · 铸渊 +// @sovereign: TCS-0002∞ · 冰朔 +// @copyright: 国作登字-2026-A-00037559 +// 铸渊开发Agent · 任务补全引擎 v2.0 // 高层面规划 → LLM补全 → 详细可执行步骤 -// ═══════════════════════════════════════ +// v2.0: 修复LLM提示词缺少target/content → 增加光湖术语上下文 → 退化继承机制 const fs = require("fs"); const path = require("path"); -/** - * 补全单条高级任务为详细步骤 - * @param {object} task - { id, action, description, context } - * @param {function} modelCaller - LLM 调用函数 (prompt) => string - * @returns {object} 补全后的任务 - */ async function expandTask(task, modelCaller) { - const prompt = [ - "你是一个开发Agent的任务补全引擎。将高级描述补全为可执行的详细步骤。", - "", - "原任务:", - " ID: " + task.id, - " 动作: " + task.action, + const taskInfo = [ + "【原任务】", + " 任务ID: " + task.id, + " 动作: " + (task.action || "未知"), + " 目标路径/命令: " + (task.target || "未指定"), + " 写入内容: " + (task.content || "未指定"), " 描述: " + (task.description || "无"), " 上下文: " + (task.context || "无"), "", - "请严格基于以上原任务拆解。不要改变原任务的action/target/content。只补充detail、depends_on等元信息。如果原任务已经足够具体,直接返回:", - "[{\"step\":1,\"action\":\"write_file|run_cmd|call_api|check\",\"target\":\"文件路径或命令\",\"detail\":\"具体做什么\",\"depends_on\":null}]" + "【光湖术语解释】", + " 铸渊 = AI开发Agent,运行在Linux服务器上,可执行Shell命令和写文件", + " ice-core = 冰核域,冰朔主权的核心域", + " BS-SG-002 = 新加坡服务器,代码face节点", + " HLDP = 光湖开发协议,所有模块代码必须包含@guardian @sovereign标签", + " 光湖语言世界 = AI原生操作系统,铸渊是其开发Agent", + "", + "【规则 · 必须遵守】", + "1. substep的target字段必须等于原任务的target字段(完整路径/完整命令),不得修改、不得用占位符替代", + "2. substep的action字段必须等于原任务的action字段", + "3. 如果原任务为 write_file 且提供了content,substep只需用相同的content", + "4. 如果原任务为 run_cmd,substep的target必须是具体的Shell命令(如 'ls -la /opt'),不能是占位符如'待指定'或'无'", + "5. 如果原任务信息已经足够具体,只返回一个substep,内容与原任务完全一致", + "6. 返回纯JSON数组,不要任何解释文字", + "", + '格式: [{"step":1,"action":"write_file|run_cmd|call_api|check","target":"文件路径或命令","detail":"具体做什么","content":"写入内容","depends_on":null}]', + "", + "现在请补全以上原任务的详细步骤:" ].join("\n"); try { - const raw = await modelCaller(prompt); + const raw = await modelCaller(taskInfo); const jsonMatch = raw.match(/\[[\s\S]*\]/); if (jsonMatch) { - const substeps = JSON.parse(jsonMatch[0]); + let substeps = JSON.parse(jsonMatch[0]); + substeps = substeps.map(ss => { + if (!ss.target || ss.target === "待指定文件路径" || ss.target === "待指定" || ss.target === "无" || ss.target === "未指定") { + console.warn("[Expander] LLM返回模糊target='" + ss.target + "', 回退到原任务target='" + task.target + "'"); + ss.target = task.target || ""; + } + if ((!ss.content || ss.content === "未指定") && task.content) { + ss.content = task.content; + } + if (!ss.detail || ss.detail.includes("需要补充") || ss.detail.includes("待指定")) { + ss.detail = task.description || ("执行: " + ss.action + " -> " + (ss.target || "?")); + } + return ss; + }); return { ...task, substeps, expanded: true, expanded_at: new Date().toISOString() }; } } catch (e) { console.warn("[Expander] LLM补全失败,退化为单步模式: " + e.message); } - // 退化:LLM不可用时,原任务本身就是一个步骤 return { ...task, - substeps: [{ step: 1, action: task.action, target: task.target || "", detail: task.description || "" }], + substeps: [{ + step: 1, + action: task.action || "unknown", + target: task.target || "", + content: task.content || "", + detail: task.description || ("执行: " + (task.action || "?") + " -> " + (task.target || "?")), + depends_on: null + }], expanded: false, expanded_at: new Date().toISOString() }; } -/** - * 完整规划补全 - * @param {object} plan - 完整规划 { plan_id, tasks[], ... } - * @param {function} modelCaller - LLM 调用函数 - * @param {string} plansDir - 规划文件存储目录 - */ async function expandPlan(plan, modelCaller, plansDir) { - console.log("[Expander] 开始补全规划: " + plan.plan_id + " · " + plan.tasks.length + "个任务"); - + console.log("[Expander v2] 开始补全规划: " + plan.plan_id + " · " + (plan.tasks?.length || 0) + "个任务"); const expandedTasks = []; - for (let i = 0; i < plan.tasks.length; i++) { + for (let i = 0; i < (plan.tasks || []).length; i++) { const task = plan.tasks[i]; - console.log("[Expander] 补全 " + (i + 1) + "/" + plan.tasks.length + ": " + task.id); + console.log("[Expander v2] 补全 " + (i + 1) + "/" + plan.tasks.length + ": " + task.id); const expanded = await expandTask(task, modelCaller); expandedTasks.push(expanded); } - plan.tasks = expandedTasks; plan._status = "expanded"; plan._expanded_at = new Date().toISOString(); - - // 写回规划文件 const planFile = path.join(plansDir, plan.plan_id + ".json"); fs.writeFileSync(planFile, JSON.stringify(plan, null, 2), "utf-8"); - - console.log("[Expander] 补全完成 · 共 " + expandedTasks.reduce((s, t) => s + (t.substeps?.length || 0), 0) + " 个子步骤"); + const totalSubsteps = expandedTasks.reduce((s, t) => s + (t.substeps?.length || 0), 0); + console.log("[Expander v2] 补全完成 · 共 " + totalSubsteps + " 个子步骤"); return plan; }