重构: 巨函数拆分 + 清理历史标记注释 + custom_prompt/停止按钮/tunnel 改进

This commit is contained in:
lxy
2026-07-31 21:36:12 +08:00
parent 365af554da
commit bd9031d35d
73 changed files with 1421 additions and 1064 deletions
@@ -4,7 +4,7 @@
//!
//! 触发条件:history_tokens > budget*0.6 且 保护区外有可压缩消息 且 未在压缩中。
//!
//! 流程(对齐阶段2 ai_chat_compress_context IPC 的 read-but-don't-mutate 模式):
//! 流程(对齐 ai_chat_compress_context IPC 的 read-but-don't-mutate 模式):
//! ① 读 active 克隆(不改 status / 不扣 token)→ 喂 LLM 出摘要;
//! ② LLM 成功 → compress_old_messages(标 compressed + 扣 token)+ insert_at(摘要 system);
//! ③ LLM 失败 → 消息状态完全不变(未改 status / 未扣 token),降级走原 build_for_request 裁剪。
@@ -17,11 +17,11 @@
//! 注:延迟 mutate 的窗口(active_msgs 读出→LLM 出摘要期间)不持锁,但 loop 串行无并发
//! (本函数独占 session_arc,工具执行/审批分支在 stream 之后),故此窗口内 messages 不变。
//!
//! 安全(FR-S1):复用 loop 顶部已 build+验证 的 provider(不再 build_provider_for 重复 resolve
//! 安全:复用 loop 顶部已 build+验证 的 provider(不再 build_provider_for 重复 resolve
//! keyring),api_key 经 df_storage::secret 闭环;summary/error payload/日志均不含 api_key。
//! is_compressing 防重入:set_compressing(true/false) 成对(LLM 调用前后均复位)。
//! 单轮问答(history_tokens 未超 0.6*budget)不触发,零行为变化。
//! F-260616-09 B 批2:messages 操作改 per_conv(设计 §4.2)
//! messages 操作改 per_conv。
use std::sync::Arc;
@@ -51,7 +51,7 @@ const PROTECT_COUNT: usize = 6;
/// 排障/对比用:置 false 即可观察无兜底时的裁剪效果。
const KEYWORD_FALLBACK_ENABLED: bool = true;
/// F-15 阶段3: 自动压缩(智能裁剪)——在 build_for_request 之前预处理。
/// 自动压缩(智能裁剪)——在 build_for_request 之前预处理。
///
/// 从 `run_agentic_loop` 抽取,行为零变更。返回值:
/// - `true`:conv 已删除,调用方应立即 `return`(退出整个 loop)。
@@ -100,7 +100,7 @@ pub(super) async fn maybe_auto_compress(
conversation_id: Some(conv_id.to_string()),
};
let _ = app_handle.emit("ai-chat-event", ev.clone());
// L3 emit 双写:tunnel subscriber(阶段2)透传 miniapp
// L3 emit 双写:tunnel subscriber透传 miniapp
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(ev);
let (active_msgs, lang) = {
let mut session = session_arc.lock().await;
@@ -168,7 +168,7 @@ pub(super) async fn maybe_auto_compress(
summary: summary.nl_summary,
};
let _ = app_handle.emit("ai-chat-event", ev.clone());
// L3 emit 双写:tunnel subscriber(阶段2)透传 miniapp
// L3 emit 双写:tunnel subscriber透传 miniapp
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(ev);
}
Ok(None) => {
@@ -216,7 +216,7 @@ pub(super) async fn maybe_auto_compress(
);
}
}
// BUG-260624-05:压缩失败不发 AiError——前端 AiError case 无条件 setStreaming(false)
// 压缩失败不发 AiError——前端 AiError case 无条件 setStreaming(false)
// 误判生成结束(后端 loop 实际继续),致"压缩后停止"。降级为 warn(上方 line 957 已有)
// + compress_old_messages 兜底释放 token + build_for_request 裁剪,loop 继续 stream_llm,
// 用户自然看到后续回复。压缩降级对用户透明(非致命错误,不该停流)。
@@ -15,9 +15,9 @@
//! - **读侧收敛**:停止按钮三态(可停 / 停中 / 停失败可重试)、MaxRoundsCard 是否弹等
//! 判别逻辑由 `ConvState` 变体直接表达,不再靠多变量组合反推。
//!
//! # 收口后(批3+)
//! # 当前架构
//!
//! 本模块是**纯逻辑、无 IO**的 enum + 转换守卫。批3 双轨收口后 `generating` bool
//! 本模块是**纯逻辑、无 IO**的 enum + 转换守卫。`generating` bool
//! 与 `CONV_STATE_ENABLED` 开关已退役,`ConvState` 成为唯一真相源:guard 接入点
//! (`GeneratingGuard` new/reset/drop 时同步迁移 `ConvState`)无条件执行迁移 + emit。
//!
@@ -52,7 +52,7 @@ use serde::{Deserialize, Serialize};
/// `ConvState` 是面向「生成生命周期」的写侧真相(写收敛)。两者正交:如 `Generating` 态
/// 同时有审批挂起时,`ConvState=Generating` 而 `SessionState=AwaitingApproval`。
///
/// 序列化(`Serialize`/`Deserialize`):批3 前端经事件总线读 enum 视图时使用(本批未接,
/// 序列化(`Serialize`/`Deserialize`):前端经事件总线读 enum 视图时使用(本批未接,
/// 预留,避免后续改动序列化兼容性)。
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
@@ -150,9 +150,7 @@ impl ConvState {
/// 审批挂起(读视图 `SessionState::AwaitingApproval`)期间 `ConvState` 仍是 `Generating`,
/// 故本方法返回 true——审批挂起不算「停止生成」。
///
/// 预留:批2+ 读侧迁移(try_continue / ai_chat_stop / 前端停止三态)消费
/// L2 读侧迁移(2026-06-22):已接入 ai_is_generating / ai_chat_stop / try_continue_agent_loop,
/// 不再标 allow(dead_code)(有真实消费方)。
/// 已接入 ai_is_generating / ai_chat_stop / try_continue_agent_loop,不再标 allow(dead_code)
pub fn is_active(self) -> bool {
matches!(self, ConvState::Generating | ConvState::Compressed)
}
@@ -162,8 +160,8 @@ impl ConvState {
/// 读侧便利方法:用于 `ai_conversation_create` / `ai_chat_send` 等入口判断
/// 「能否接新请求」。`Error` 态视为可接(用户重试即从 Error 起步)。
///
/// 双轨收口批1(2026-06-25):chat 域入口拦截(ai_regenerate / ai_chat_send /
/// ai_chat_edit)已接入,作真实读侧方法消费。删除 `allow(dead_code)` 标注。
/// chat 域入口拦截(ai_regenerate / ai_chat_send /
/// ai_chat_edit)已接入,作真实读侧方法消费。
pub fn can_accept_request(self) -> bool {
matches!(self, ConvState::Idle | ConvState::Error)
}
+1 -1
View File
@@ -9,7 +9,7 @@ use crate::commands::ai::knowledge_inject::inject_knowledge_into_prompt;
use crate::commands::ai::{AiChatEvent, ErrorType, SessionState, GoalEntry};
use super::conv_state::ConvState;
/// BUG-260617-05: try_continue_agent_loop 续跑判定所需 session 字段的一次性快照。
/// try_continue_agent_loop 续跑判定所需 session 字段的一次性快照。
struct ContinueSnapshot {
is_generating: bool,
has_pending: bool,
File diff suppressed because it is too large Load Diff