清理旧策划委派语义
删除 project-planning 的澄清与用户修订跳转说明 保留做游戏 Agent 的静态委派返工语义 更新运行时诊断测试中的旧策划身份夹具
This commit is contained in:
@@ -781,7 +781,7 @@ mod provider_reconciliation_diagnostic_tests {
|
||||
let directory = tempfile::tempdir().expect("diagnostic directory");
|
||||
let snapshot = AgentRuntimeProviderRequestSnapshot {
|
||||
project_id: "project-1".to_string(),
|
||||
agent_id: "project-planning".to_string(),
|
||||
agent_id: "project-supervisor".to_string(),
|
||||
task_id: "task-1".to_string(),
|
||||
session_id: "session-1".to_string(),
|
||||
run_id: "run-1".to_string(),
|
||||
@@ -805,7 +805,7 @@ mod provider_reconciliation_diagnostic_tests {
|
||||
usage: None,
|
||||
tool_calls: vec![platform_llm::LlmToolCall {
|
||||
id: "call-1".to_string(),
|
||||
name: "runtime_tool_plan_submit_gdd".to_string(),
|
||||
name: "runtime_tool_agent_message".to_string(),
|
||||
arguments: "{\"path\":\"C:\\\\private\\\\argument\"}".to_string(),
|
||||
}],
|
||||
responses_output: Vec::new(),
|
||||
|
||||
@@ -201,39 +201,17 @@ pub(crate) fn observe_agent_runtime_agent_message(
|
||||
}
|
||||
}
|
||||
|
||||
/// 委派 task 末尾那句「你在这条链路上的位置」。三种跳的语义互不相同,共用一句话
|
||||
/// 就会说谎,所以这里把它显式化。
|
||||
/// 委派 task 末尾那句「你在这条链路上的位置」。返工和普通委派的语义不同,单独保留。
|
||||
///
|
||||
/// - `Repair`:质量返工,`repair_depth` 上限 1,「唯一返工轮」是真的。而且这句话是
|
||||
/// 做游戏链路的**授权信号**——`design-foundation` / `art-director` /
|
||||
/// `art-asset-plan` 的角色提示词都把「任务正文明确标识这是带 repairOfDelegationId
|
||||
/// 的唯一返工轮」当作 `replaceExisting=true` 的唯一许可(见 agent/prompt.rs 的三处
|
||||
/// 角色 prompt)。这一支逐字不能动。
|
||||
/// - `PlanClarification`:澄清续跑不消耗 `repair_depth`,预算是
|
||||
/// `static_delegate_clarification_round_limit_at`(plan 链路 3 轮)。master 只有一道
|
||||
/// 平坦的 depth <= 1 门,那时「唯一返工轮」对澄清跳也成立;本仓库改成按谱系分类后
|
||||
/// 把预算抬到 3,这句话就变成了假天花板——生产实测 4 次澄清续跑全部命中它,命中后
|
||||
/// 全部直接出稿,没有任何一个 run 走到第 2 轮。
|
||||
/// - `UserRevision`:用户在审批卡上点「修改 / 退回」后的修订轮。它同样带
|
||||
/// `repairOfDelegationId`,但 `repair_depth` 防的是 runaway agent,而这一跳每一轮
|
||||
/// 都由人触发——人本身就是循环边界,所以 `static_delegate_lineage_counters` 早就
|
||||
/// 把 depth/round 原样继承了。缺的是这句话:走 `Repair` 分支时用户第一次点修改就
|
||||
/// 会被告知「这是唯一返工轮」,和澄清跳当初那个假天花板是同一个错误。原型对应的是
|
||||
/// `USER_REVISION_SOFT_LIMIT = 16`,且超过只提示、不拒绝。
|
||||
/// - `None`:普通委派,不加这一段。
|
||||
pub(in crate::agent) enum StaticDelegateHopNote<'a> {
|
||||
None,
|
||||
Repair {
|
||||
original_delegation_id: &'a str,
|
||||
},
|
||||
UserRevision {
|
||||
original_delegation_id: &'a str,
|
||||
},
|
||||
PlanClarification {
|
||||
original_delegation_id: &'a str,
|
||||
rounds_used: u32,
|
||||
rounds_limit: u32,
|
||||
},
|
||||
Repair { original_delegation_id: &'a str },
|
||||
}
|
||||
|
||||
impl StaticDelegateHopNote<'_> {
|
||||
@@ -247,32 +225,6 @@ impl StaticDelegateHopNote<'_> {
|
||||
StaticDelegateHopNote::Repair {
|
||||
original_delegation_id,
|
||||
} => format!("\n\n这是对已认领委派 {original_delegation_id} 的唯一返工轮。"),
|
||||
StaticDelegateHopNote::UserRevision {
|
||||
original_delegation_id,
|
||||
} => format!(
|
||||
"\n\n这是对已认领委派 {original_delegation_id} 的用户修订轮,由用户在审批卡上提出,不是质量返工,不消耗返工深度,也不重置澄清轮次。按任务正文里的用户意见原文修订同一份 GDD 谱系后重新提交;用户看过新稿还可以再次提出修改,这不是最后一轮,不要因此压缩改动或提前收尾。"
|
||||
),
|
||||
// 预算用尽:planning_coordinator 出卡时会用
|
||||
// `current_round >= 3` 直接拒掉第四张卡,所以这里不能再邀请提问,
|
||||
// 只能要求收稿——语义上等价于原型的 INJ_MUST_DRAFT_ROUNDS。
|
||||
StaticDelegateHopNote::PlanClarification {
|
||||
original_delegation_id,
|
||||
rounds_used,
|
||||
rounds_limit,
|
||||
} if rounds_used >= rounds_limit => format!(
|
||||
"\n\n这是对已认领委派 {original_delegation_id} 的澄清续跑,不是返工轮。已用澄清轮次 {rounds_used}/{rounds_limit},澄清预算已用尽:本轮不得再输出 AGC_NEEDS_USER_INPUT_V1 信封,剩余空白按默认建议补齐并标 default_pending,立即提交 GDD。"
|
||||
),
|
||||
// 轮号必须和 planning_coordinator 出卡时的期望一致:那边用
|
||||
// `validate_exact_plan_clarification_question(.., current_round + 1)`,
|
||||
// current_round 就是本 delivery 的谱系轮次,也就是这里的 rounds_used。
|
||||
StaticDelegateHopNote::PlanClarification {
|
||||
original_delegation_id,
|
||||
rounds_used,
|
||||
rounds_limit,
|
||||
} => format!(
|
||||
"\n\n这是对已认领委派 {original_delegation_id} 的澄清续跑,不是返工轮,不消耗返工深度。已用澄清轮次 {rounds_used}/{rounds_limit}。仍有会实质改变结果的空白且预算未用尽时,可以继续以 AGC_NEEDS_USER_INPUT_V1 信封退出:questions 恰好一题,header 写成「第{next_round}轮·当前要决定:<主题>」,轮号必须是 {next_round},主题写这一轮真正要定的那件事。预算已用尽,或剩余空白能由默认建议覆盖且不影响首个可玩闭环时,立即提交 GDD。",
|
||||
next_round = rounds_used.saturating_add(1),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1523,122 +1475,3 @@ pub(crate) fn observe_agent_runtime_agent_spawn_isolated(
|
||||
.map(|value| redact_agent_runtime_project_paths(root, &value, 3_600)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// 委派 task 末尾那句话是两条链路的合同,不能共用一份文案。
|
||||
///
|
||||
/// 上半条钉做游戏链路:`design-foundation` / `art-director` / `art-asset-plan`
|
||||
/// 的角色提示词把「任务正文明确标识这是带 repairOfDelegationId 的唯一返工轮」
|
||||
/// 当作 `replaceExisting=true` 的唯一授权信号,改一个字就会让返工轮拿不到许可。
|
||||
///
|
||||
/// 下半条钉立项策划链路:澄清续跑不是返工轮,套用返工文案等于告诉策划子 Agent
|
||||
/// 「你只剩这一轮」——这正是生产上 4 次澄清续跑之后无一走到第 2 轮的原因。
|
||||
/// 同时钉住轮号:`planning_coordinator` 出卡时按 `rounds_used + 1` 校验 header,
|
||||
/// 这里写进 task 的必须是同一个数,否则第 2 轮信封会当场被拒。
|
||||
/// 用户修订轮同样不能套返工文案。
|
||||
///
|
||||
/// 「唯一返工轮」防的是 runaway agent,而这一跳由用户在审批卡上亲手点出来——人本身
|
||||
/// 就是循环边界,`static_delegate_lineage_counters` 早就把 depth/round 原样继承了。
|
||||
/// 套用返工文案就是告诉策划子 Agent「用户只能改这一次」,和澄清跳当初那个假天花板
|
||||
/// 是同一个错误。原型对应的是软阈值 16 次、超过只提示不拒绝。
|
||||
#[test]
|
||||
fn user_revision_hop_note_is_not_the_repair_round_note() {
|
||||
let revision = render_static_delegate_task_contract(
|
||||
"任务",
|
||||
"project-supervisor",
|
||||
"run-1",
|
||||
"delegation-new",
|
||||
&["交付 game/fast_gdd.md".to_string()],
|
||||
&["game/fast_gdd.md".to_string()],
|
||||
StaticDelegateHopNote::UserRevision {
|
||||
original_delegation_id: "delegation-old",
|
||||
},
|
||||
)
|
||||
.expect("render user revision hop note");
|
||||
assert!(
|
||||
!revision.contains("唯一返工轮"),
|
||||
"用户修订轮不得复用返工文案,否则子 Agent 以为用户只能改这一次:{revision}"
|
||||
);
|
||||
assert!(
|
||||
revision.contains("不消耗返工深度"),
|
||||
"必须写明它不吃返工额度:{revision}"
|
||||
);
|
||||
assert!(
|
||||
revision.contains("不是最后一轮"),
|
||||
"必须写明用户还能再改,否则子 Agent 会把多条意见攒到一轮改完:{revision}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plan_clarification_hop_note_is_not_the_repair_round_note() {
|
||||
let repair = render_static_delegate_task_contract(
|
||||
"任务",
|
||||
"project-supervisor",
|
||||
"run-1",
|
||||
"delegation-new",
|
||||
&["交付产物".to_string()],
|
||||
&["assets/art-spec.png".to_string()],
|
||||
StaticDelegateHopNote::Repair {
|
||||
original_delegation_id: "delegation-old",
|
||||
},
|
||||
)
|
||||
.expect("render repair");
|
||||
assert!(
|
||||
repair.contains("这是对已认领委派 delegation-old 的唯一返工轮。"),
|
||||
"返工轮文案是做游戏链路 replaceExisting 的授权信号,必须逐字保留:{repair}"
|
||||
);
|
||||
|
||||
let clarification = render_static_delegate_task_contract(
|
||||
"任务",
|
||||
"project-supervisor",
|
||||
"run-1",
|
||||
"delegation-new",
|
||||
&["交付 game/fast_gdd.md".to_string()],
|
||||
&["game/fast_gdd.md".to_string()],
|
||||
StaticDelegateHopNote::PlanClarification {
|
||||
original_delegation_id: "delegation-old",
|
||||
rounds_used: 1,
|
||||
rounds_limit: 3,
|
||||
},
|
||||
)
|
||||
.expect("render clarification");
|
||||
assert!(
|
||||
!clarification.contains("唯一返工轮"),
|
||||
"澄清续跑不得复用返工文案,否则策划子 Agent 以为只剩这一轮:{clarification}"
|
||||
);
|
||||
assert!(
|
||||
clarification.contains("已用澄清轮次 1/3"),
|
||||
"澄清续跑必须写明已用轮次与上限:{clarification}"
|
||||
);
|
||||
assert!(
|
||||
clarification.contains("第2轮·当前要决定:"),
|
||||
"task 里的轮号必须等于 planning_coordinator 校验 header 时用的 rounds_used + 1:{clarification}"
|
||||
);
|
||||
|
||||
let exhausted = render_static_delegate_task_contract(
|
||||
"任务",
|
||||
"project-supervisor",
|
||||
"run-1",
|
||||
"delegation-new",
|
||||
&["交付 game/fast_gdd.md".to_string()],
|
||||
&["game/fast_gdd.md".to_string()],
|
||||
StaticDelegateHopNote::PlanClarification {
|
||||
original_delegation_id: "delegation-old",
|
||||
rounds_used: 3,
|
||||
rounds_limit: 3,
|
||||
},
|
||||
)
|
||||
.expect("render exhausted clarification");
|
||||
assert!(
|
||||
exhausted.contains("澄清预算已用尽"),
|
||||
"预算用尽时必须要求收稿,出卡侧会直接拒掉第四张卡:{exhausted}"
|
||||
);
|
||||
assert!(
|
||||
!exhausted.contains("第4轮·当前要决定:"),
|
||||
"预算用尽时不得再给出下一轮 header,那是一张永远递不上去的卡:{exhausted}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,8 +275,7 @@ fn agent_runtime_native_capability_registry() -> Result<&'static CapabilityRegis
|
||||
///
|
||||
/// `"__all_agents__"` 是个不对应任何真实 Agent 的哨兵:走这条路径拿到的是
|
||||
/// 未按身份收窄的完整函数目录。生产代码必须调用 `_for_agent` 版本并传入真实
|
||||
/// `agentId`,否则按身份收窄的工具面(如 `project-planning` 的 exact
|
||||
/// allowlist)会被静默绕开。这里用 `#[cfg(test)]` 把「忘记改用 `_for_agent`」
|
||||
/// `agentId`,否则按身份收窄的工具面会被静默绕开。这里用 `#[cfg(test)]` 把「忘记改用 `_for_agent`」
|
||||
/// 从运行时静默扩权变成编译期错误。
|
||||
#[cfg(test)]
|
||||
pub(crate) fn build_agent_runtime_native_function_tools() -> Result<Vec<LlmFunctionTool>, String> {
|
||||
|
||||
Reference in New Issue
Block a user