/** * 把「人类对这次权限请求的结论」渲染成模型能读懂的一段话。 * * # 为什么单独一个模块 * * 三条路径都要给模型同一句话:工具拦截(bash/write…)、无挂起 worker 时的通知投递、 * 以及主动询问(kind=question)。而 2026-09-13 的线上缺陷正是这句话里**没有人类的备注**: * * - 用户原话:「被拒绝的 agent 好像看不到我给授权的备注」 * - 现场证据(pi 会话转录):模型收到的工具结果只有 * `用户拒绝了这次 bash 调用`;而人类那封决策邮件里写着 * `拒绝\n\n备注: 我说了让你拉取仓库到program下你听不懂吗` * - 后果:模型不知道要改什么,把同一条命令换个写法又问了一遍(实测连问 9 次)。 * * 备注在 `index.mjs → pool.mjs → worker.mjs` 三处被逐个丢掉,所以判据必须落在 * **模型最终看到的那段文本**上(这个函数的返回值),而不是"某个字段有没有传"。 */ /** 模型最终看到的那句"被拒了",附上人类说明与等人期间新到的邮件。 */ export function renderDecisionReason({ toolName, decision, note = '', waiting = [] }) { const base = decision === 'shutdown' ? '用户未及决策(桥已关停)' : `用户拒绝了这次 ${toolName} 调用`; const parts = [base]; const text = String(note ?? '').trim(); if (text) parts.push(`用户的说明:${text}`); const fresh = Array.isArray(waiting) ? waiting.filter(Boolean) : []; if (fresh.length) { parts.push([ `【等人审批期间新到的邮件 ${fresh.length} 封,尚未标记已读】`, ...fresh, '请先用 read_inbox 读这些邮件,再决定下一步 —— 里面可能是对当前做法的更正。', ].join('\n')); } return parts.join('\n\n'); }