重构: F-09 batch4 启用多会话上线(决策e真并发·F-09完整)

- IPC签名加conv_id: ai_is_generating/ai_chat_send/ai_chat_force_send/ai_chat_stop + 内部移除active一致性校验(后台conv可操作)
- 删switch readonly分支 + 删ai_conversation_create强制结束旧loop(决策e,切走旧loop不退出)
- 删双写桥接+顶层字段: messages/generating/stop_flag/notify/iteration_used/agent_language/model_override/session_trust全删,per_conv唯一真相源 + 删双写代码(全模块)+ 删fallback读 + pending_approvals retain目标conv
- 前端: api/ai.ts+useAiSend/useAiWindow传conv_id
保留: session_state(SW预留标allow)/readonly(前端不读);零调用方预留按用户指导保留
主代兜底: cargo check --workspace 0 + vue-tsc 0 + test 98 + grep顶层删除/per_conv唯一印证
F-09完整(batch1 PerConvState+batch2迁移+batch5限流调整+batch8恢复+batch4上线);双会话人工验收留用户
This commit is contained in:
2026-06-19 03:03:48 +08:00
parent 2b40f65ef2
commit d899c58682
10 changed files with 345 additions and 522 deletions

View File

@@ -42,35 +42,24 @@ pub fn run() {
let mut session = session_arc.lock().await;
// F-260616-09 B 批8(设计 §3 batch8 + §5.2):遍历 per_conv(HashMap)清多 conv
// 残留 generating(HMR/dev 热载场景多 conv 并发跑 loop 致多 conv 卡 generating)。
// 批2 前:仅读 active per_conv.generating 单值;批8 改遍历全部 per_conv 各归各复位
// 顶层 session.generating(批2 双写桥接)同步复位(批4 IPC 迁移后顶层移除)。
let mut dirty_convs: Vec<String> = session
// 批4:per_conv 唯一真相源,删顶层 session.generating 双写复位(顶层字段已退役)
let dirty_convs: Vec<String> = session
.per_conv
.iter()
.filter(|(_, c)| c.generating)
.map(|(id, _)| id.clone())
.collect();
let was_generating = !dirty_convs.is_empty() || session.generating;
let was_generating = !dirty_convs.is_empty();
// 复位每个残留 generating 的 conv(批8 多 conv 全覆盖)。
for cid in &dirty_convs {
if let Some(conv) = session.per_conv.get_mut(cid) {
conv.generating = false;
}
}
// 顶层双写复位(批2 桥接:IPC ai_is_generating 等仍读顶层,须同步)。
session.generating = false;
// BUG-260619-06 修复: clear 致冷启动 restore 重建审批丢失(restore 填充后 clear 无条件清空,
// 重启后待审批工具全丢)。改 retain 仅清非 recovered(本次会话/HMR 死 pending),
// 保留 restore 重建(recovered=true,audit.rs:331),对齐 switchConversation retain 保护意图。
session.pending_approvals.retain(|_, a| !a.recovered);
// active_conversation_id 兜底入 dirty_convs:批2 双写期顶层 generating=true 但
// per_conv 为空(理论上不会发生,防御性保证 active conv 至少收一个 AiCompleted
// 复位前端 streaming/generatingConvId)。
if let Some(active) = session.active_conversation_id.clone() {
if !active.is_empty() && !dirty_convs.contains(&active) {
dirty_convs.push(active);
}
}
drop(session);
if was_generating {
// 补偿事件:每个残留 conv 各发一个 AiCompleted(按 conversation_id 路由),