feat: 添加 topic_id 字段到消息结构,优化消息处理逻辑

This commit is contained in:
oudecheng 2026-06-12 12:22:21 +08:00
parent 87fc8cc3b7
commit cedd8b2a69
5 changed files with 29 additions and 0 deletions

View File

@ -202,6 +202,8 @@ pub enum WsOutbound {
task_id: String,
description: String,
subagent_type: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
topic_id: Option<String>,
},
#[serde(rename = "session_established")]
SessionEstablished { session_id: String },

View File

@ -172,6 +172,7 @@ pub(crate) fn ws_outbound_from_outbound_message(message: &OutboundMessage) -> Ve
task_id: message.metadata.get("task_id").cloned().unwrap_or_default(),
description: message.metadata.get("task_description").cloned().unwrap_or_default(),
subagent_type: message.metadata.get("task_subagent_type").cloned().unwrap_or_default(),
topic_id: message.metadata.get("topic_id").cloned(),
}],
}
}

View File

@ -250,6 +250,7 @@ impl DefaultSubAgentRuntime {
let mut metadata = HashMap::new();
metadata.insert("subagent_task_id".to_string(), session.id.clone());
metadata.insert("is_subagent_event".to_string(), "true".to_string());
metadata.insert("topic_id".to_string(), session.parent_topic_id.clone().unwrap_or_default());
let emitter = Arc::new(PersistingEmittedMessageHandler::new(
SubAgentEmitter {
@ -424,6 +425,7 @@ impl SubAgentRuntime for DefaultSubAgentRuntime {
metadata.insert("task_id".to_string(), session.id.clone());
metadata.insert("task_description".to_string(), session.description.clone());
metadata.insert("task_subagent_type".to_string(), session.subagent_type.clone());
metadata.insert("topic_id".to_string(), session.parent_topic_id.clone().unwrap_or_default());
let event = OutboundMessage {
channel: session.parent_channel_name.clone(),

View File

@ -181,6 +181,15 @@ export function useChat(): UseChatReturn {
return undefined
}
// Extract topic_id from a message if present
const getTopicId = (message: WsOutbound): string | undefined => {
if (message.type === 'tool_call' || message.type === 'tool_result'
|| message.type === 'tool_pending' || message.type === 'assistant_response') {
return (message as ToolCall | ToolResult | ToolPending | AssistantResponse).topic_id
}
return undefined
}
// Convert a server message to ChatMessage (extracted from handleServerMessage logic)
const serverMessageToChatMessage = (message: WsOutbound): ChatMessage | null => {
switch (message.type) {
@ -311,12 +320,20 @@ export function useChat(): UseChatReturn {
appendToSubAgentViewMessage(message)
return
}
// 丢弃其他子智能体的消息,避免 fall through 到主消息处理
if (msgSubagentTaskId) {
return
}
}
// In main view, skip sub-agent messages (they belong to sub-agent view).
// But use the task_id to associate with the running task tool card.
const msgSubagentTaskId = getSubagentTaskId(message)
if (msgSubagentTaskId) {
// 只 backfill 当前话题的 task tool_call避免跨话题串扰
const msgTopicId = getTopicId(message)
if (msgTopicId && msgTopicId !== selectedTopicRef.current) return
setMessages((prev) => {
for (let i = prev.length - 1; i >= 0; i--) {
if (prev[i].type === 'tool_call' && prev[i].toolName === 'task' && !prev[i].subagentTaskId) {
@ -340,6 +357,9 @@ export function useChat(): UseChatReturn {
case 'task_started': {
const msg = message as TaskStarted
// 只 backfill 当前话题的 task tool_call避免跨话题串扰
if (msg.topic_id && msg.topic_id !== selectedTopicRef.current) break
// 立即更新对应的 task tool_call让用户可以点击查看实时进度
setMessages((prev) => {
for (let i = prev.length - 1; i >= 0; i--) {
@ -602,6 +622,7 @@ export function useChat(): UseChatReturn {
const selectTopic = useCallback((topicId: string) => {
setSelectedTopic(topicId)
setMessages([])
setSubAgentView(null)
}, [])
const createTopic = useCallback((title?: string): Command => {
@ -647,6 +668,7 @@ export function useChat(): UseChatReturn {
setTopics([])
setSelectedTopic(null)
setMessages([])
setSubAgentView(null)
setIsLoading(true)
}, [selectedChannel])
@ -656,6 +678,7 @@ export function useChat(): UseChatReturn {
setTopics([])
setSelectedTopic(null)
setMessages([])
setSubAgentView(null)
setIsLoading(true)
}, [selectedSessionId])

View File

@ -100,6 +100,7 @@ export interface TaskStarted {
task_id: string
description: string
subagent_type: string
topic_id?: string
}
export interface SessionEstablished {