修复: AiCompleted 携带 pinned_goals 根治目标面板刷新
This commit is contained in:
@@ -823,6 +823,15 @@ pub(crate) async fn run_agentic_loop(
|
||||
}
|
||||
}
|
||||
|
||||
// 对话透明化 L1:拍快照供 AiCompleted 事件携带,前端直接读取 pinned_goals 无需等 loadConversations
|
||||
let pinned_goals_snapshot: Vec<String> = {
|
||||
let session = session_arc.lock().await;
|
||||
session
|
||||
.conv_read(&conv_id)
|
||||
.map(|c| c.pinned_goals.clone())
|
||||
.unwrap_or_default()
|
||||
};
|
||||
|
||||
// F-260616-13: system_prompt 是 run_agentic_loop 的不变参数(整个 loop 期间文本不变),
|
||||
// 其 token 估算在 loop 外算一次缓存复用,避免每轮/每次重试重复 estimate_text(低收益优化,行为不变)。
|
||||
let sys_tokens = TokenEstimator::default().estimate_text(&system_prompt);
|
||||
@@ -854,7 +863,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
spawn_ensure_title(&provider_config, &db, &conv_id, &app_handle, &session_arc, &llm_concurrency);
|
||||
guard.reset().await;
|
||||
// generating 复位后再 emit Completed:保证前端收事件时后端已可接下一条(发送队列续发不被"正在生成中"拒绝)
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage.total_tokens, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()) });
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage.total_tokens, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()), pinned_goals: pinned_goals_snapshot.clone() });
|
||||
// L3 emit 双写:入口 stop 的 AiCompleted publish 到事件总线(EVENT_BUS_ENABLED 门控在 publish 内)。
|
||||
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiCompleted {
|
||||
total_tokens: usage.total_tokens,
|
||||
@@ -862,6 +871,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
completion_tokens: tokens.completion(),
|
||||
incomplete: None,
|
||||
conversation_id: Some(conv_id.clone()),
|
||||
pinned_goals: pinned_goals_snapshot.clone(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -1432,6 +1442,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
completion_tokens: tokens.completion(),
|
||||
conversation_id: Some(conv_id.clone()),
|
||||
incomplete: Some(true),
|
||||
pinned_goals: pinned_goals_snapshot.clone(),
|
||||
});
|
||||
// L3 emit 双写:MidStream 保文 AiCompleted publish 到事件总线(门控在 publish 内)。
|
||||
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiCompleted {
|
||||
@@ -1440,6 +1451,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
completion_tokens: tokens.completion(),
|
||||
incomplete: None,
|
||||
conversation_id: Some(conv_id.clone()),
|
||||
pinned_goals: pinned_goals_snapshot.clone(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -1500,7 +1512,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
spawn_ensure_title(&provider_config, &db, &conv_id, &app_handle, &session_arc, &llm_concurrency);
|
||||
guard.reset().await;
|
||||
// generating 复位后再 emit Completed:保证前端收事件时后端已可接下一条(发送队列续发不被"正在生成中"拒绝)
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage.total_tokens, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()) });
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage.total_tokens, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()), pinned_goals: pinned_goals_snapshot.clone() });
|
||||
// L3 emit 双写:stream 后 stop 的 AiCompleted publish 到事件总线(门控在 publish 内)。
|
||||
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiCompleted {
|
||||
total_tokens: usage.total_tokens,
|
||||
@@ -1508,6 +1520,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
completion_tokens: tokens.completion(),
|
||||
incomplete: None,
|
||||
conversation_id: Some(conv_id.clone()),
|
||||
pinned_goals: pinned_goals_snapshot.clone(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -1813,7 +1826,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
|
||||
guard.reset().await;
|
||||
// generating 复位后再 emit Completed:落库/标题/提炼已在后台,前端立即感知完成
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage_total, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()) });
|
||||
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage_total, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()), pinned_goals: pinned_goals_snapshot.clone() });
|
||||
// L3 emit 双写:正常完成 AiCompleted publish 到事件总线(EVENT_BUS_ENABLED 门控在 publish 内,
|
||||
// 无消费者空转留批3 真实消费者接入)。AiTextDelta/AiToolCall* 高频事件不双写(无消费者空转)。
|
||||
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiCompleted {
|
||||
@@ -1822,6 +1835,7 @@ pub(crate) async fn run_agentic_loop(
|
||||
completion_tokens: tokens.completion(),
|
||||
incomplete: None,
|
||||
conversation_id: Some(conv_id.clone()),
|
||||
pinned_goals: pinned_goals_snapshot.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1939,12 +1953,14 @@ pub(crate) async fn try_continue_agent_loop(
|
||||
let is_generating = conv.map(|c| c.conv_state.is_active()).unwrap_or(false);
|
||||
let agent_language = conv.and_then(|c| c.agent_language.clone());
|
||||
let model_override = conv.and_then(|c| c.model_override.clone());
|
||||
let pinned_goals_snapshot = conv.map(|c| c.pinned_goals.clone()).unwrap_or_default();
|
||||
ContinueSnapshot {
|
||||
is_generating,
|
||||
has_pending,
|
||||
pending_conv_id,
|
||||
agent_language,
|
||||
model_override,
|
||||
pinned_goals_snapshot,
|
||||
}
|
||||
};
|
||||
let should_continue = snap.is_generating && !snap.has_pending;
|
||||
@@ -1971,6 +1987,7 @@ pub(crate) async fn try_continue_agent_loop(
|
||||
completion_tokens: 0,
|
||||
incomplete: None,
|
||||
conversation_id: Some(emit_conv_id),
|
||||
pinned_goals: snap.pinned_goals_snapshot.clone(),
|
||||
};
|
||||
let _ = app.emit("ai-chat-event", ev.clone());
|
||||
// L3 emit 双写:tunnel subscriber(阶段2)透传 miniapp
|
||||
@@ -2062,6 +2079,7 @@ pub(crate) async fn try_continue_agent_loop(
|
||||
completion_tokens: 0,
|
||||
incomplete: None,
|
||||
conversation_id: Some(conv_id_owned.clone()),
|
||||
pinned_goals: snap.pinned_goals_snapshot.clone(),
|
||||
};
|
||||
let _ = app.emit("ai-chat-event", ev.clone());
|
||||
// L3 emit 双写:tunnel subscriber(阶段2)透传 miniapp
|
||||
@@ -2097,6 +2115,8 @@ struct ContinueSnapshot {
|
||||
pending_conv_id: Option<String>,
|
||||
agent_language: Option<String>,
|
||||
model_override: Option<String>,
|
||||
/// 对话透明化 L1:快照 pinned_goals 供 AiCompleted emit 携带
|
||||
pinned_goals_snapshot: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user