diff --git a/src/gateway/ws.rs b/src/gateway/ws.rs index 73234bf..7ca9543 100644 --- a/src/gateway/ws.rs +++ b/src/gateway/ws.rs @@ -459,12 +459,13 @@ async fn handle_inbound( } // 加载子智能体任务消息 if let Some(task_session_id) = response.metadata.get("task_session_id") { - if let Err(e) = send_task_messages(&store, task_session_id, sender).await { + // 提前提取 task_id,用于给历史消息打标记 + let task_id = response.metadata.get("task_id").cloned().unwrap_or_default(); + if let Err(e) = send_task_messages(&store, task_session_id, sender, Some(task_id.clone())).await { tracing::warn!(error = %e, task_session_id = %task_session_id, "Failed to send task messages"); } // 发送 TaskMessagesLoaded 元数据 - let task_id = response.metadata.get("task_id").cloned().unwrap_or_default(); let description = response.metadata.get("task_description").cloned().unwrap_or_default(); let subagent_type = response.metadata.get("task_subagent_type").cloned().unwrap_or_default(); let status = response.metadata.get("task_status").cloned().unwrap_or_default(); @@ -496,7 +497,7 @@ async fn handle_inbound( &load_chat_channel, load_chat_id, ); - if let Err(e) = send_task_messages(&store, &session_id, sender).await { + if let Err(e) = send_task_messages(&store, &session_id, sender, None).await { tracing::warn!( error = %e, channel = %load_chat_channel, @@ -591,13 +592,19 @@ async fn send_task_messages( store: &Arc, session_id: &str, sender: &mpsc::Sender, + subagent_task_id: Option, ) -> Result<(), Box> { let messages = store.load_messages(session_id)?; tracing::info!(session_id = %session_id, message_count = messages.len(), "Sending task messages"); for msg in messages { - let outbound = chat_message_to_ws_outbound(&msg); + let mut outbound = chat_message_to_ws_outbound(&msg); + if let Some(ref task_id) = subagent_task_id { + if let Some(ref mut ob) = outbound { + set_subagent_task_id(ob, task_id); + } + } if let Some(outbound) = outbound { let _ = sender.send(outbound).await; } @@ -606,6 +613,27 @@ async fn send_task_messages( Ok(()) } +/// 给 WsOutbound 消息注入 subagent_task_id(仅对有该字段的变体生效) +fn set_subagent_task_id(outbound: &mut WsOutbound, task_id: &str) { + match outbound { + WsOutbound::AssistantResponse { + subagent_task_id, .. + } + | WsOutbound::ToolCall { + subagent_task_id, .. + } + | WsOutbound::ToolResult { + subagent_task_id, .. + } + | WsOutbound::ToolPending { + subagent_task_id, .. + } => { + *subagent_task_id = Some(task_id.to_string()); + } + _ => {} // 其他变体没有 subagent_task_id 字段 + } +} + /// 将 ChatMessage 转换为 WsOutbound fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option { use crate::bus::message::ToolMessageState; diff --git a/web/src/hooks/useChat.ts b/web/src/hooks/useChat.ts index d75fb9a..c450b3a 100644 --- a/web/src/hooks/useChat.ts +++ b/web/src/hooks/useChat.ts @@ -251,11 +251,11 @@ export function useChat(): UseChatReturn { return } - // Route messages to sub-agent view: - // - Messages without subagent_task_id = loaded history, always accept - // - Messages with subagent_task_id = live emitter, only accept if matching + // Only accept messages explicitly tagged with matching subagent_task_id. + // History messages are now tagged by the backend (send_task_messages), + // and live sub-agent messages are tagged by SubAgentEmitter. const msgSubagentTaskId = getSubagentTaskId(message) - if (!msgSubagentTaskId || msgSubagentTaskId === currentSubAgentView.taskId) { + if (msgSubagentTaskId && msgSubagentTaskId === currentSubAgentView.taskId) { appendToSubAgentViewMessage(message) } return