diff --git a/src/gateway/session.rs b/src/gateway/session.rs index 8da0ed1..c2bc751 100644 --- a/src/gateway/session.rs +++ b/src/gateway/session.rs @@ -131,7 +131,15 @@ impl BusToolCallEmitter { }; let session_id = crate::storage::persistent_session_id(&self.channel_name, &self.chat_id); - let scope_key = &session_id; + // 优先用 topic_id(与 list_todos handler 和 tool 内存状态保持一致) + let scope_key = self + .metadata + .get("topic_id") + .filter(|t| !t.is_empty()) + .cloned() + .unwrap_or_else(|| session_id.clone()); + + let topic_id = self.metadata.get("topic_id").filter(|t| !t.is_empty()).cloned(); let records: Vec = todos_array .iter() @@ -140,7 +148,7 @@ impl BusToolCallEmitter { id: item.get("id")?.as_str()?.to_string(), scope_key: scope_key.clone(), session_id: session_id.clone(), - topic_id: None, + topic_id: topic_id.clone(), content: item.get("content")?.as_str()?.to_string(), status: item.get("status")?.as_str()?.to_string(), priority: item.get("priority")?.as_str()?.to_string(), @@ -156,7 +164,7 @@ impl BusToolCallEmitter { "BusToolCallEmitter: persisting todo_write result" ); - if let Err(e) = self.store.replace_todos(scope_key, &records) { + if let Err(e) = self.store.replace_todos(&scope_key, &records) { tracing::warn!(error = %e, %scope_key, "Failed to persist todo list from BusToolCallEmitter"); } } diff --git a/web/src/App.tsx b/web/src/App.tsx index 2536bb1..23ce1d0 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -332,11 +332,20 @@ function App() { const skillCmd = requestSkillList() handleCommand(skillCmd) sendMessage({ type: 'command', payload: JSON.stringify(skillCmd) }) - const todoCmd = requestTodoList() - handleCommand(todoCmd) - sendMessage({ type: 'command', payload: JSON.stringify(todoCmd) }) } - }, [status, handleCommand, sendMessage, requestMemoryList, requestSkillList, requestTodoList]) + }, [status, handleCommand, sendMessage, requestMemoryList, requestSkillList]) + + // 连接就绪、切换 topic、或进出子代理视图时刷新 todo 列表 + const prevTodoTriggerRef = useRef('') + useEffect(() => { + if (status !== 'connected') return + const key = `${selectedTopic ?? ''}|${subAgentView?.taskId ?? ''}` + if (key === prevTodoTriggerRef.current) return + prevTodoTriggerRef.current = key + const todoCmd = requestTodoList() + handleCommand(todoCmd) + sendMessage({ type: 'command', payload: JSON.stringify(todoCmd) }) + }, [status, selectedTopic, subAgentView, handleCommand, sendMessage, requestTodoList]) const handleRefreshMemories = useCallback(() => { const cmd = requestMemoryList()