Merge branch 'feat/clarification-round-split' into feat/five_min_design
This commit is contained in:
@@ -15,6 +15,12 @@ const STATIC_DELEGATE_EXPECTED_ARTIFACT_MAX_CHARS: usize = 240;
|
||||
const STATIC_DELEGATE_MAX_EVIDENCE: usize = 16;
|
||||
const STATIC_DELEGATE_USER_INPUT_PREFIX: &str = "AGC_NEEDS_USER_INPUT_V1\n";
|
||||
const STATIC_DELEGATE_USER_INPUT_MAX_RESPONSE_CHARS: usize = 500;
|
||||
// 澄清轮次上限按 source 区分:诉求只来自策划节点,game-chat 单主路径定位零打扰,
|
||||
// 从未承诺给它 3 轮预算,因此取 1;其它 source(包括 Project Supervisor 常规协作)取 3。
|
||||
const STATIC_DELEGATE_CLARIFICATION_ROUND_LIMIT_DEFAULT: u32 = 3;
|
||||
const STATIC_DELEGATE_CLARIFICATION_ROUND_LIMIT_GAME_CHAT: u32 = 1;
|
||||
// 链上重放的防环 / 防越界上限,远大于设计允许的最大 7 跳,纯粹是安全阀。
|
||||
const STATIC_DELEGATE_LINEAGE_MAX_HOPS: usize = 32;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
@@ -1080,6 +1086,91 @@ pub(crate) fn game_chat_art_delivery_gap_at(
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// 唯一权威判据:某条 delivery 是否处于「等待用户澄清」状态——也就是说,从它出发的
|
||||
/// 下一跳(若存在)应当被归类为澄清 continuation,而不是质量返工。
|
||||
/// `validate_static_delegate_repair_request_at` 与
|
||||
/// `validate_static_delegate_clarification_continuation_at` 共用这一个判据源,
|
||||
/// 避免两处口径漂移。
|
||||
fn static_delegate_original_is_awaiting_clarification(
|
||||
delivery: &StaticDelegateDeliveryRecord,
|
||||
) -> bool {
|
||||
delivery.structured_result.as_ref().is_some_and(|result| {
|
||||
result.contract_status == StaticDelegateContractStatus::NeedsUserInput
|
||||
})
|
||||
}
|
||||
|
||||
/// 沿 repair_of_delegation_id 反向重放整条链,现算目标 delivery 的
|
||||
/// (repair_depth, clarification_round)。两个维度都是运行时派生值,故意不落盘:
|
||||
/// - R3(链根,repair_of_delegation_id 为 None):depth = 0,round = 0。
|
||||
/// - R1(澄清跳:父节点处于 awaiting-clarification):round = parent.round + 1,
|
||||
/// depth 原样继承(不重置),否则可以插一次澄清洗掉返工深度,变成无限返工。
|
||||
/// - R2(返工跳:父节点不处于 awaiting-clarification):depth = parent.depth + 1,
|
||||
/// round 重置为 0,因为返工后策划节点重新开工,不能因为返工吃掉预设的澄清轮次预算。
|
||||
///
|
||||
/// 防环 / 防越界:反向重放阶段一旦遇到重复 id、缺失的上游节点,或跳数超出
|
||||
/// STATIC_DELEGATE_LINEAGE_MAX_HOPS,立即 fail closed,返回 (u32::MAX, u32::MAX),
|
||||
/// 使调用方的深度门 / 轮次门必然拒绝,而不是静默放行。
|
||||
pub(crate) fn static_delegate_lineage_counters(
|
||||
deliveries: &[StaticDelegateDeliveryRecord],
|
||||
delegation_id: &str,
|
||||
) -> (u32, u32) {
|
||||
let mut chain: Vec<&StaticDelegateDeliveryRecord> = Vec::new();
|
||||
let mut seen_ids: std::collections::BTreeSet<&str> = std::collections::BTreeSet::new();
|
||||
let mut current_id = delegation_id;
|
||||
loop {
|
||||
if !seen_ids.insert(current_id) || chain.len() >= STATIC_DELEGATE_LINEAGE_MAX_HOPS {
|
||||
return (u32::MAX, u32::MAX);
|
||||
}
|
||||
let Some(node) = deliveries
|
||||
.iter()
|
||||
.find(|delivery| delivery.delegation_id == current_id)
|
||||
else {
|
||||
return (u32::MAX, u32::MAX);
|
||||
};
|
||||
chain.push(node);
|
||||
match node.repair_of_delegation_id.as_deref() {
|
||||
Some(parent_id) => current_id = parent_id,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
// chain 目前是 [目标 .. 根],反转成 [根 .. 目标] 便于按 R1/R2/R3 正向传播。
|
||||
chain.reverse();
|
||||
let mut depth = 0u32;
|
||||
let mut round = 0u32;
|
||||
for parent in &chain[..chain.len().saturating_sub(1)] {
|
||||
if static_delegate_original_is_awaiting_clarification(*parent) {
|
||||
round += 1;
|
||||
} else {
|
||||
depth += 1;
|
||||
round = 0;
|
||||
}
|
||||
}
|
||||
(depth, round)
|
||||
}
|
||||
|
||||
/// 澄清轮次上限只按发起请求所在 Run 的 source 区分(详见常量注释),
|
||||
/// 与仓库已有的 game-chat 分支先例(见 agent/runtime_tools/delegation.rs 的
|
||||
/// may_be_game_chat 判定)同源:source 缺失 binding 时按非 game-chat 处理。
|
||||
fn static_delegate_clarification_round_limit_at(
|
||||
root: &Path,
|
||||
parent_agent_id: &str,
|
||||
parent_run_id: &str,
|
||||
) -> Result<u32, String> {
|
||||
let is_game_chat = read_game_creator_agent_runtime_run_profile_binding(
|
||||
root,
|
||||
parent_agent_id,
|
||||
parent_run_id,
|
||||
)?
|
||||
.is_some_and(|binding| {
|
||||
binding.source.trim() == AGENT_RUNTIME_SUPERVISOR_GAME_CHAT_SOURCE
|
||||
});
|
||||
Ok(if is_game_chat {
|
||||
STATIC_DELEGATE_CLARIFICATION_ROUND_LIMIT_GAME_CHAT
|
||||
} else {
|
||||
STATIC_DELEGATE_CLARIFICATION_ROUND_LIMIT_DEFAULT
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn validate_static_delegate_repair_request_at(
|
||||
root: &Path,
|
||||
parent_agent_id: &str,
|
||||
@@ -1116,7 +1207,15 @@ pub(crate) fn validate_static_delegate_repair_request_at(
|
||||
if original.target_agent_id != target_agent_id {
|
||||
return Err("静态委派返工必须交回原专业 Agent".to_string());
|
||||
}
|
||||
if original.repair_of_delegation_id.is_some() {
|
||||
let (original_repair_depth, original_clarification_round) =
|
||||
static_delegate_lineage_counters(&deliveries, &original.delegation_id);
|
||||
if static_delegate_original_is_awaiting_clarification(original) {
|
||||
let clarification_round_limit =
|
||||
static_delegate_clarification_round_limit_at(root, parent_agent_id, parent_run_id)?;
|
||||
if original_clarification_round >= clarification_round_limit {
|
||||
return Err("静态委派澄清轮次已达上限".to_string());
|
||||
}
|
||||
} else if original_repair_depth >= 1 {
|
||||
return Err("静态委派返工深度最多为 1".to_string());
|
||||
}
|
||||
if original.acceptance_criteria != acceptance_criteria
|
||||
@@ -1180,9 +1279,7 @@ pub(crate) fn validate_static_delegate_clarification_continuation_at(
|
||||
read_static_delegate_delivery_at(root, repair_of_delegation_id)?.ok_or_else(|| {
|
||||
format!("澄清 continuation 引用的原 delivery 不存在:{repair_of_delegation_id}")
|
||||
})?;
|
||||
let needs_user_input = original.structured_result.as_ref().is_some_and(|result| {
|
||||
result.contract_status == StaticDelegateContractStatus::NeedsUserInput
|
||||
});
|
||||
let needs_user_input = static_delegate_original_is_awaiting_clarification(&original);
|
||||
if !needs_user_input {
|
||||
if !continuation_of.is_empty()
|
||||
|| !input_questions_sha.is_empty()
|
||||
@@ -1572,7 +1669,7 @@ pub(crate) fn read_static_delegate_delivery_at(
|
||||
Ok(Some(record))
|
||||
}
|
||||
|
||||
fn list_static_delegate_deliveries_at(
|
||||
pub(crate) fn list_static_delegate_deliveries_at(
|
||||
root: &Path,
|
||||
) -> Result<Vec<StaticDelegateDeliveryRecord>, String> {
|
||||
let dir = resolve_local_project_path(root, STATIC_DELEGATE_DELIVERY_DIR)?;
|
||||
@@ -1669,7 +1766,7 @@ fn list_static_delegate_claims_at(root: &Path) -> Result<Vec<StaticDelegateClaim
|
||||
Ok(claims)
|
||||
}
|
||||
|
||||
fn write_static_delegate_delivery_at(
|
||||
pub(crate) fn write_static_delegate_delivery_at(
|
||||
root: &Path,
|
||||
record: &StaticDelegateDeliveryRecord,
|
||||
) -> Result<(), String> {
|
||||
|
||||
+1490
-32
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user