重构: aichat 双轨状态机收口 + AiCompressed 事件拆分
- generating bool + CONV_STATE_ENABLED 开关双轨退役,ConvState enum 单一真相源 - can_accept_request 接入 chat 域入口(覆盖 Stopping 竞态,严谨于 is_active) - AiCompressed 拆 AiManualCompressed/AiAutoCompressed(治自动压缩误触桌面toast+刷新) - convStates/getConvState 下沉 aiShared.ts 破循环依赖
This commit is contained in:
@@ -199,8 +199,17 @@ pub enum AiChatEvent {
|
||||
AiContextCleared { conversation_id: Option<String> },
|
||||
/// F-15 阶段2 手动 LLM 压缩开始:前端展示压缩中态(spinner/禁用按钮防重入)。
|
||||
AiCompressing { conversation_id: Option<String> },
|
||||
/// F-15 阶段2 手动 LLM 压缩完成:摘要已插入消息首位,前端可展示摘要 + 移除压缩中态。
|
||||
AiCompressed { conversation_id: Option<String>, summary: String },
|
||||
/// F-15 阶段2 手动 LLM 压缩完成:摘要已插入消息首位,前端弹 toast + 刷新视图回填摘要。
|
||||
///
|
||||
/// 治 Task#1(BUG-260624-05):自动压缩路径误用此变体致桌面误弹 toast+每次发送误刷,
|
||||
/// 现拆为 AiManualCompressed(手动 IPC,弹 toast) + AiAutoCompressed(loop 自动,静默)。
|
||||
/// emit 点:ai_chat_compress_context IPC 的 3 处(空会话/无 active/LLM 成功主路径)。
|
||||
AiManualCompressed { conversation_id: Option<String>, summary: String },
|
||||
/// F-15 阶段2 自动 LLM 压缩完成(agentic loop 触发,治 Task#1):对桌面端静默——
|
||||
/// 桌面 useAiContext 仅复位 isCompressing(防按钮卡死兜底),不弹 toast 不 switchConversation。
|
||||
/// 摘要 system 消息已由后端 insert_at,后续 stream 自然带出,无需整会话刷新。
|
||||
/// miniapp 仍插摘要气泡(对端发生压缩告知用户)。
|
||||
AiAutoCompressed { conversation_id: Option<String>, summary: String },
|
||||
/// L1 求助协议(aichat 体验与 agent 能力系统化重构 §2.3,2026-06-21):
|
||||
///
|
||||
/// agent 断路器(§2.2)熔断 / 自省(识别"我反复失败")时发,区别于 prompt 教 AI
|
||||
@@ -257,8 +266,8 @@ pub enum AiChatEvent {
|
||||
/// (入口/guard reset/drop 迁移)后 emit 此事件,前端 status union 据此更新展示态
|
||||
/// (替代散布的 generating bool 派生判断,收敛状态机读侧到事件流)。
|
||||
///
|
||||
/// 渐进/兜底:`CONV_STATE_ENABLED` 开关门控 —— off 时不 emit(前端按旧 bool 行为派生,
|
||||
/// 向后兼容);on 时此事件与既有 generating 行为双轨,前端可按需切换消费源。
|
||||
/// 批3 双轨收口:`CONV_STATE_ENABLED` 开关与 generating bool 已退役,emit 无条件执行
|
||||
/// (enum 单一真相源,无 off 降级分支)。前端按 conv_state 事件流派生展示态。
|
||||
/// `conv_state` 序列化为 snake_case(idle/generating/stopping/error/compressed),
|
||||
/// 供前端 union discriminator 直接使用。
|
||||
AiConvStateChanged {
|
||||
@@ -514,7 +523,9 @@ impl AiSession {
|
||||
.any(|a| a.conversation_id.as_deref() == Some(conv_id));
|
||||
if has_pending {
|
||||
SessionState::AwaitingApproval
|
||||
} else if self.conv_read(conv_id).map(|c| c.generating).unwrap_or(false) {
|
||||
} else if self.conv_read(conv_id).map(|c| c.conv_state.is_active()).unwrap_or(false) {
|
||||
// 读侧(双轨收口批2):改读 conv_state.is_active()(Generating+Compressed),判断是否在
|
||||
// 活跃生成。is_active() 与原 generating 语义一致(压缩期间 loop 仍活跃,应判为 Streaming)。
|
||||
SessionState::Streaming
|
||||
} else {
|
||||
SessionState::Idle
|
||||
@@ -557,7 +568,8 @@ mod tests_f09_per_conv {
|
||||
#[test]
|
||||
fn test_per_conv_state_new() {
|
||||
let s = PerConvState::new();
|
||||
assert!(!s.generating, "generating 初值应为 false");
|
||||
// 批3 收口:generating bool 已退役,生成态初值校验改读 conv_state(应为 Idle)。
|
||||
assert_eq!(s.conv_state, ConvState::Idle, "conv_state 初值应为 Idle");
|
||||
assert_eq!(s.iteration_used, 0, "iteration_used 初值应为 0");
|
||||
assert!(s.agent_language.is_none(), "agent_language 初值应为 None");
|
||||
assert!(s.model_override.is_none(), "model_override 初值应为 None");
|
||||
@@ -587,7 +599,8 @@ mod tests_f09_per_conv {
|
||||
// 首次 conv() 创建
|
||||
let ptr_first = {
|
||||
let s = session.conv("conv-a");
|
||||
assert!(!s.generating);
|
||||
// 批3 收口:generating bool 已退役,首建会话生成态应为 Idle。
|
||||
assert_eq!(s.conv_state, ConvState::Idle);
|
||||
assert_eq!(s.iteration_used, 0);
|
||||
s as *const PerConvState
|
||||
};
|
||||
@@ -747,11 +760,9 @@ mod tests_f09_per_conv {
|
||||
pub struct PerConvState {
|
||||
/// 对话历史(ContextManager:会话级消息真相源,裁剪仅影响发送视图)
|
||||
pub messages: ContextManager,
|
||||
/// 是否正在生成
|
||||
pub generating: bool,
|
||||
/// L2 统一状态机:对话生命周期状态(单一真相源,批2 持久化供读侧/前端消费)。
|
||||
/// 写收敛:经 GeneratingGuard/入口 transition_to 守卫迁移,非直接赋值。
|
||||
/// 与 generating bool 双轨过渡(bool 核心复位,enum 视图),批2+ 读侧迁移后 enum 主。
|
||||
/// 批3 双轨收口:generating bool 已退役,此 enum 成为生成态唯一真相源。
|
||||
pub conv_state: ConvState,
|
||||
/// 停止信号(会话级):ai_chat_stop 置位,agentic loop / stream_llm 检测后尽快退出
|
||||
pub stop_flag: Arc<AtomicBool>,
|
||||
@@ -802,7 +813,6 @@ impl PerConvState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
messages: ContextManager::new(ContextConfig::default()),
|
||||
generating: false,
|
||||
conv_state: ConvState::Idle,
|
||||
stop_flag: Arc::new(AtomicBool::new(false)),
|
||||
notify: Arc::new(tokio::sync::Notify::new()),
|
||||
|
||||
Reference in New Issue
Block a user