无头链路能跑审批的修改/退回,不再只能投 approve
`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 <noreply@anthropic.com>
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user