fix(ws): 历史加载时对账 task running 占位,修复刷新/切话题后子代理卡片永远显示运行中
DB messages 表的 task tool_result 固化在 spawn 时刻的 running 状态,完成信号只更新 pending_subagents 表;send_topic_history 原样发送导致刷新后卡片退回黄色运行中。 新增 reconcile_running_in_messages:发送前按 pending_subagents 实际状态替换发送副本, 复用 session.rs 提取/格式化函数(改为 pub(crate)),不落库且幂等,无占位时零查询。
This commit is contained in:
parent
867b7df409
commit
692cc93075
@ -881,7 +881,7 @@ impl Session {
|
||||
/// 纯文本格式: `running, task_id=xxx. ...`
|
||||
///
|
||||
/// 返回 (task_id, is_json)。仅当 status=="running" 时才提取(只对账 running 占位)。
|
||||
fn extract_task_id_from_content(content: &str) -> Option<(String, bool)> {
|
||||
pub(crate) fn extract_task_id_from_content(content: &str) -> Option<(String, bool)> {
|
||||
// 尝试 JSON 格式
|
||||
let json_start = content.find('{')?;
|
||||
if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(&content[json_start..]) {
|
||||
@ -912,7 +912,7 @@ fn extract_task_id_from_content(content: &str) -> Option<(String, bool)> {
|
||||
///
|
||||
/// JSON 格式:更新 JSON 中的 status 字段(保持前端 parseTaskResult 兼容)。
|
||||
/// 纯文本格式:替换为描述性文本(向后兼容)。
|
||||
fn format_reconciled_content(task_id: &str, status: &str, is_json: bool) -> String {
|
||||
pub(crate) fn format_reconciled_content(task_id: &str, status: &str, is_json: bool) -> String {
|
||||
if is_json {
|
||||
// 更新 JSON 中的 status 字段,保持前端 parseTaskResult 能正确解析
|
||||
let placeholder = match status {
|
||||
|
||||
@ -806,7 +806,13 @@ async fn send_topic_history(
|
||||
task_repository: &Arc<dyn TaskRepository>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// 加载话题消息,按 session_id 过滤,避免混入子智能体消息
|
||||
let messages = store.load_messages_for_topic_full(topic_id, Some(session_id))?;
|
||||
let mut messages = store.load_messages_for_topic_full(topic_id, Some(session_id))?;
|
||||
|
||||
// 对账 running 占位:DB 中的 task tool_result 永远保持 spawn 时的 running 状态
|
||||
// (实时完成信号只更新前端内存与 pending_subagents 表),若不替换,
|
||||
// 刷新/切话题后前端卡片会永远显示"运行中"。与 Session::reconcile_running_placeholders
|
||||
// 同语义,仅改发送副本,不落库。
|
||||
reconcile_running_in_messages(&mut messages, store, topic_id);
|
||||
|
||||
tracing::info!(topic_id = %topic_id, message_count = messages.len(), "Sending topic history");
|
||||
|
||||
@ -877,6 +883,52 @@ async fn send_topic_history(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 发送前对账消息列表中的 task "running" 占位。
|
||||
///
|
||||
/// DB messages 表中的 task tool_result 行固化在 spawn 时刻的 running 状态,
|
||||
/// 完成信号只更新 pending_subagents 表;此处按该表的实际状态替换发送副本,
|
||||
/// 避免前端刷新/切话题后卡片永远显示"运行中"。仍为 running 的保持原样。
|
||||
fn reconcile_running_in_messages(
|
||||
messages: &mut [crate::bus::ChatMessage],
|
||||
store: &Arc<crate::storage::SessionStore>,
|
||||
topic_id: &str,
|
||||
) {
|
||||
let has_running_placeholder = messages.iter().any(|m| {
|
||||
m.role == "tool" && crate::gateway::session::extract_task_id_from_content(&m.content).is_some()
|
||||
});
|
||||
if !has_running_placeholder {
|
||||
return; // 无需查询 DB
|
||||
}
|
||||
|
||||
let pending = match store.list_pending_subagents(topic_id, None) {
|
||||
Ok(records) => records,
|
||||
Err(e) => {
|
||||
tracing::warn!(error = %e, %topic_id, "Failed to query pending_subagents for history reconciliation");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let status_map: std::collections::HashMap<&str, &str> = pending
|
||||
.iter()
|
||||
.map(|r| (r.task_id.as_str(), r.status.as_str()))
|
||||
.collect();
|
||||
|
||||
for msg in messages.iter_mut() {
|
||||
if msg.role != "tool" {
|
||||
continue;
|
||||
}
|
||||
let Some((task_id, is_json)) = crate::gateway::session::extract_task_id_from_content(&msg.content)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
match status_map.get(task_id.as_str()) {
|
||||
Some(&status) if status != "running" => {
|
||||
msg.content = crate::gateway::session::format_reconciled_content(&task_id, status, is_json);
|
||||
}
|
||||
_ => {} // 不存在(已清理)或仍在运行:保留原占位
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载并发送子智能体任务的历史消息
|
||||
async fn send_task_messages(
|
||||
store: &Arc<crate::storage::SessionStore>,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user