From 92e571e1dcef3646829663742c7f8e52b52fae56 Mon Sep 17 00:00:00 2001 From: Linghong Date: Wed, 26 Aug 2026 09:04:30 +0000 Subject: [PATCH] =?UTF-8?q?=E6=97=A0=E5=A4=B4=E9=93=BE=E8=B7=AF=E8=83=BD?= =?UTF-8?q?=E8=B7=91=E5=AE=A1=E6=89=B9=E7=9A=84=E4=BF=AE=E6=94=B9/?= =?UTF-8?q?=E9=80=80=E5=9B=9E=EF=BC=8C=E4=B8=8D=E5=86=8D=E5=8F=AA=E8=83=BD?= =?UTF-8?q?=E6=8A=95=20approve?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `agent-swarm-test-chat.mjs --plan` 的自动审批把动作写死成 approve,原注释让人 「要跑那两条分支就手工调 --plan-gdd-decide」。但那条路走不通:decide 要求 plan 根 run 仍是当前唯一 active 的,而它恰好是本进程持有的 CLI 子进程——CLI 一死, 再 decide 就是 PLAN_STALE_APPROVAL,实测过。于是 revise/reject 在无头侧没有任何 入口,e43133875 / 9e2648893 / b27ffce9b 三条修复都只能靠单测。 加 AGC_PLAN_GDD_DECISION + AGC_PLAN_GDD_COMMENT 两个环境变量,默认仍是 approve, 既有调用行为一字不变。原注释那条约束保留并落成断言:非 approve 时缺意见直接抛, 不给机器编一段的机会——意见必须由跑的人自己给。`runCapturedCargo` 顺带支持 stdin, 决定报告从写死的「已批准」改成打印实际动作。 用它跑通了一条完整真链路(两轮澄清 → 出稿 → 修改 → 返工 → v2): - session successor 与 gdd.v2.json 同一秒落盘,phase=awaiting_gdd_approval、 latestSubmittedRef=v2、activeRunId 已清空,不再 PLAN_SESSION_RECOVERY_REQUIRED - 意见原文进了 Supervisor 会话,也进了返工委派正文 - 标题「脉冲避航:微型核心危局」→「エネルギー・ランナー」,意见是「改成日文」 Co-Authored-By: Claude Opus 5 --- .../scripts/agent-swarm-test-chat.mjs | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/apps/ai-game-creator-shell/scripts/agent-swarm-test-chat.mjs b/apps/ai-game-creator-shell/scripts/agent-swarm-test-chat.mjs index 97d19625f..e170b07c6 100644 --- a/apps/ai-game-creator-shell/scripts/agent-swarm-test-chat.mjs +++ b/apps/ai-game-creator-shell/scripts/agent-swarm-test-chat.mjs @@ -143,7 +143,12 @@ export const usage = `用法: --plan 走「做方案」立项策划入口,不做游戏,不做产物验收和试玩 --timeout-minutes <分钟> 设置本次执行期限;自动任务默认 50 分钟,--plan 默认 6 分钟,手工模式默认不限时 --dry-run 只检查目录发现和项目准备,不启动 LLM - -h, --help 显示帮助`; + -h, --help 显示帮助 + +环境变量: + AGC_PLAN_GDD_DECISION 审批卡自动应答动作,默认 approve;revise/reject 必须 + 同时用 AGC_PLAN_GDD_COMMENT 给出真实修改意见 + AGC_PLAN_GDD_COMMENT revise/reject 的意见原文`; function readOptionValue(args, index, option) { const value = args[index + 1]?.trim(); @@ -911,12 +916,15 @@ export function parseSettledSwarmTurnReport(output) { async function runCapturedCargo( cliArguments, setActiveChild, - { timeoutMs = null, label = 'Cargo 子命令' } = {}, + { timeoutMs = null, label = 'Cargo 子命令', stdin = null } = {}, ) { const child = spawnChild(cargoCommand, buildCargoCliArguments(cliArguments), { - stdio: ['ignore', 'pipe', 'pipe'], + stdio: [stdin === null ? 'ignore' : 'pipe', 'pipe', 'pipe'], }); setActiveChild(child); + if (stdin !== null) { + child.stdin.end(stdin); + } let stdout = ''; let stderr = ''; child.stdout.setEncoding('utf8'); @@ -1007,7 +1015,9 @@ async function runTaskCargo( let planGddApprovalPromise = null; const startPlanGddApproval = () => { planGddApprovalStarted = true; - console.log('[自动审批] 检测到 Fast GDD 审批位,正在提交 approve'); + console.log( + `[自动审批] 检测到 Fast GDD 审批位,正在提交 ${resolvePlanGddAutoDecision().action}`, + ); planGddApprovalPromise = onPlanGddApprovalWait() .then((value) => { planGddApproval = value; @@ -1842,13 +1852,30 @@ export function parsePlanGddDecisionOutput(output) { ); } -// 审批卡是这条链路唯一的人类判据,所以自动应答只投 approve,且只在投影确实有一张 -// 待决定审批时出手。revise/reject 需要一段真实的修改意见,让机器编一段等于把判据 -// 换成噪声;要跑那两条分支就手工调 --plan-gdd-decide。 +// 审批卡是这条链路唯一的人类判据,所以自动应答默认只投 approve,且只在投影确实有 +// 一张待决定审批时出手。revise/reject 需要一段真实的修改意见,让机器编一段等于把 +// 判据换成噪声——所以那两条分支只在跑的人自己用 AGC_PLAN_GDD_COMMENT 给出意见时 +// 才走。手工调 --plan-gdd-decide 也能达到同样效果,但那要求 plan 根 run 仍然活着, +// 而它恰好是本进程持有的 CLI 子进程。 export function planGddAutoApprovalIsPending(state) { return Boolean(state?.pendingApproval); } +export function resolvePlanGddAutoDecision(env = process.env) { + const action = (env.AGC_PLAN_GDD_DECISION ?? 'approve').trim(); + if (!['approve', 'revise', 'reject'].includes(action)) { + throw new Error('AGC_PLAN_GDD_DECISION 只能是 approve / revise / reject'); + } + const comment = (env.AGC_PLAN_GDD_COMMENT ?? '').trim(); + if (action === 'approve') return { action, comment: null }; + if (!comment) { + throw new Error( + `${action} 必须同时设 AGC_PLAN_GDD_COMMENT 提供真实修改意见`, + ); + } + return { action, comment }; +} + async function settlePlanGddApproval( projectPath, runtimeConfigPath, @@ -1875,18 +1902,21 @@ async function settlePlanGddApproval( if (!planGddAutoApprovalIsPending(before)) { return { decided: false, state: before }; } + const { action, comment } = resolvePlanGddAutoDecision(); const decision = await runCapturedCargo( [ '--config-dir', runtimeConfigPath, '--plan-gdd-decide', projectPath, - 'approve', + action, + ...(comment === null ? [] : ['--stdin']), ], setActiveChild, { timeoutMs: planGddApprovalTimeoutMs, label: 'Fast GDD 审批决定', + stdin: comment, }, ); if (decision.code !== 0 || decision.signal) { @@ -1926,7 +1956,7 @@ async function reportPlanGddApproval(approval) { return; } console.log( - ` [已批准] outcome=${approval.receipt.outcome} v${approval.receipt.decisionRef.version} 投影状态=${state.state}`, + ` [已决定 ${approval.receipt.decisionRef.action}] outcome=${approval.receipt.outcome} v${approval.receipt.decisionRef.version} 投影状态=${state.state}`, ); if (approval.recovered) { console.log(