修复审批前思考过程的阶段归属
在用户回合边界立即绑定上一轮 reasoning 到对应 assistant 消息 新增审批边界回归测试,防止思考过程错误堆积到下一阶段底部
This commit is contained in:
@@ -150,14 +150,26 @@ fn persisted_design_reasoning_entries(session: &DesignSession) -> Vec<DesignReas
|
||||
let mut group_index = 0;
|
||||
let mut assistant_index = 0;
|
||||
let mut sequence = 0_u64;
|
||||
let mut current_reasoning = Vec::new();
|
||||
let mut pending_reasoning = Vec::new();
|
||||
let mut current_reasoning: Vec<DesignReasoningEntry> = Vec::new();
|
||||
let mut pending_reasoning: Vec<DesignReasoningEntry> = Vec::new();
|
||||
let mut saw_response_output = false;
|
||||
|
||||
for item in &session.history {
|
||||
if item.get("role").and_then(Value::as_str) == Some("user") {
|
||||
if !pending_reasoning.is_empty() || !current_reasoning.is_empty() {
|
||||
pending_reasoning.append(&mut current_reasoning);
|
||||
// A user item closes the previous turn. Resolve its reasoning
|
||||
// against that turn's last assistant message before moving to
|
||||
// the next group; otherwise it is incorrectly attached to the
|
||||
// next turn and rendered at the bottom as an orphan.
|
||||
let assistant_id = assistant_groups
|
||||
.get(group_index)
|
||||
.and_then(|ids| ids.last())
|
||||
.cloned();
|
||||
for mut entry in pending_reasoning.drain(..) {
|
||||
entry.message_id = assistant_id.clone();
|
||||
entries.push(entry);
|
||||
}
|
||||
}
|
||||
group_index += 1;
|
||||
assistant_index = 0;
|
||||
@@ -1638,6 +1650,53 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn persisted_reasoning_stays_with_the_turn_before_an_approval_boundary() {
|
||||
let mut session = new_design_session("project", "quality");
|
||||
session.messages = vec![
|
||||
DesignMessage {
|
||||
id: "turn-1:user".into(),
|
||||
role: "user".into(),
|
||||
text: "第一轮需求".into(),
|
||||
},
|
||||
DesignMessage {
|
||||
id: "turn-1:assistant".into(),
|
||||
role: "assistant".into(),
|
||||
text: "第一轮已提交审批".into(),
|
||||
},
|
||||
DesignMessage {
|
||||
id: "turn-2:user".into(),
|
||||
role: "user".into(),
|
||||
text: "用户已批准,进入下一阶段".into(),
|
||||
},
|
||||
DesignMessage {
|
||||
id: "turn-2:assistant".into(),
|
||||
role: "assistant".into(),
|
||||
text: "查询工作阶段".into(),
|
||||
},
|
||||
];
|
||||
session.history = vec![
|
||||
json!({"role":"user", "content":"第一轮需求"}),
|
||||
json!({"type":"reasoning", "id":"before-approval", "content":[{"type":"reasoning_text", "text":"审批前的思考"}]}),
|
||||
json!({"type":"message", "role":"assistant", "content":[{"type":"output_text", "text":"第一轮已提交审批"}]}),
|
||||
json!({"role":"user", "content":"用户已批准,进入下一阶段"}),
|
||||
json!({"type":"reasoning", "id":"after-approval", "content":[{"type":"reasoning_text", "text":"审批后的思考"}]}),
|
||||
json!({"type":"message", "role":"assistant", "content":[{"type":"output_text", "text":"查询工作阶段"}]}),
|
||||
];
|
||||
|
||||
let entries = persisted_design_reasoning_entries(&session);
|
||||
assert_eq!(
|
||||
entries
|
||||
.iter()
|
||||
.map(|entry| (entry.id.as_str(), entry.message_id.as_deref()))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
("before-approval", Some("turn-1:assistant")),
|
||||
("after-approval", Some("turn-2:assistant")),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn scripted_design_provider_emits_reasoning_without_persisting_it() {
|
||||
let (_temp, root, _resources) = init_design_project();
|
||||
|
||||
Reference in New Issue
Block a user