修复: FR-S3 approve decision 非空校验 + FR-R1 switchConversation 切换 token

- FR-S3: approve_human_approval 加 decision 非空校验(防 "" 透传;HumanNode options 非空时还校验 ∈ options)
- FR-R1: switchConversation 加 _latestSwitchId token,过期响应丢弃(防快速连点 A→B 后返回的 A 覆盖 B messages)
来源 fullstack-review §2/§4(核实确认);cargo/vue-tsc 0 err
This commit is contained in:
2026-06-14 17:03:13 +08:00
parent 3c5f702288
commit 698a874709
2 changed files with 10 additions and 0 deletions

View File

@@ -185,6 +185,10 @@ pub async fn approve_human_approval(
decision: String, decision: String,
comment: Option<String>, comment: Option<String>,
) -> Result<(), String> { ) -> Result<(), String> {
// decision 非空校验(FR-S3: 防 "" 透传;HumanNode options 非空时还校验 ∈ options)
if decision.trim().is_empty() {
return Err("审批决策不能为空".to_string());
}
// 发送审批响应到事件总线 // 发送审批响应到事件总线
let response = HumanApprovalResponse { let response = HumanApprovalResponse {
execution_id: execution_id.clone(), execution_id: execution_id.clone(),

View File

@@ -40,10 +40,16 @@ async function newConversation() {
notifyConversationChanged() notifyConversationChanged()
} }
// 切换 token:快速连点 A→B 时,后返回的 A 响应按 token 丢弃,防 messages 错配(FR-R1)
let _latestSwitchId = 0
/** 切换到指定会话:加载历史消息(含 tool_calls 回填 + tool_result 映射 + pending 审批恢复) */ /** 切换到指定会话:加载历史消息(含 tool_calls 回填 + tool_result 映射 + pending 审批恢复) */
export async function switchConversation(id: string) { export async function switchConversation(id: string) {
const mySwitchId = ++_latestSwitchId
// 允许生成中切换:后台继续生成,事件按 conversation_id 路由不污染当前视图 // 允许生成中切换:后台继续生成,事件按 conversation_id 路由不污染当前视图
const detail = await aiApi.switchConversation(id) const detail = await aiApi.switchConversation(id)
// 过期响应丢弃(用户已切到别的对话,防 A 后返回覆盖 B)
if (mySwitchId !== _latestSwitchId) return
state.activeConversationId = id state.activeConversationId = id
void appSettings.set('df-ai-active-conv', id) void appSettings.set('df-ai-active-conv', id)