refactor(todo): 统一子代理 scope_key 为全局唯一的 task_id
- 修改 list_todos 处理器,子代理使用 task_id 作为 scope_key,替代原先的 sub:{parent_session_id}:{task_id}
- 调整 todo_write 的 scope_key_from_context 函数,子/孙代理使用 task_id 隔离,避免与父代理污染
- 修正子任务消息的 task_id 传递逻辑,在 useChat hook 中为子代理视图的孙子任务回填正确的 task_id
- 清理 MessageBubble 组件中多余的 isSubAgent 变量声明
This commit is contained in:
parent
421714dfa3
commit
e585ec71b1
@ -41,10 +41,10 @@ impl CommandHandler for ListTodosCommandHandler {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// 子代理:scope_key = sub:{parent_session_id}:{task_id}
|
||||
// 子代理:scope_key = task_id(全局唯一,与 todo_write 保持一致)
|
||||
// 主代理:scope_key = topic_id.unwrap_or(session_id)
|
||||
let scope_key = if let (Some(tid), Some(parent_sid)) = (task_id.as_deref(), ctx.session_id.as_deref()) {
|
||||
format!("sub:{}:{}", parent_sid, tid)
|
||||
let scope_key = if let Some(tid) = task_id.as_deref() {
|
||||
tid.to_string()
|
||||
} else {
|
||||
ctx.topic_id
|
||||
.as_deref()
|
||||
|
||||
@ -330,10 +330,14 @@ impl Tool for TodoWriteTool {
|
||||
|
||||
/// 计算 scope_key:
|
||||
/// - 主代理 (nesting_depth == 0):优先 topic_id,否则 session_id
|
||||
/// - 子/孙代理 (nesting_depth > 0):使用 session_id 隔离,避免污染父代理 todo
|
||||
/// - 子/孙代理 (nesting_depth > 0):使用 task_id 隔离(全局唯一,与 list_todos 保持一致)
|
||||
pub(crate) fn scope_key_from_context(context: &ToolContext) -> Option<String> {
|
||||
if context.nesting_depth > 0 {
|
||||
context.session_id.clone().filter(|s| !s.is_empty())
|
||||
// 使用 task_id 而不是 session_id 作为 scope_key。
|
||||
// session_id 对于孙智能体包含父链(如 sub:sub:root:parent:task),
|
||||
// 而 list_todos handler 用根 session + task_id 拼接,两者不匹配。
|
||||
// task_id 是全局唯一的 UUID(task:xxx),直接使用可避免层级不一致。
|
||||
context.task_id.clone().filter(|s| !s.is_empty())
|
||||
} else {
|
||||
let tid = context.topic_id.as_deref().filter(|t| !t.is_empty());
|
||||
let sid = context.session_id.as_deref().filter(|s| !s.is_empty());
|
||||
|
||||
@ -364,7 +364,6 @@ export function MessageBubble({ message, onNavigateToSubAgent, showThinking = tr
|
||||
|
||||
const isTaskTool = message.toolName === 'task'
|
||||
const taskResult = isTaskTool && hasResult ? parseTaskResult(displayContent) : null
|
||||
const isSubAgent = !!message.subagentTaskId
|
||||
const subagentType = (message.arguments as Record<string, unknown> | null)?.subagent_type as string || 'general'
|
||||
const taskDescription = (message.arguments as Record<string, unknown> | null)?.description as string || ''
|
||||
const taskPrompt = (message.arguments as Record<string, unknown> | null)?.prompt as string || ''
|
||||
|
||||
@ -395,6 +395,34 @@ export function useChat(): UseChatReturn {
|
||||
return
|
||||
}
|
||||
|
||||
// Backfill grandchild task_id on task tool_call in sub-agent view.
|
||||
// When the sub-agent spawns a grandchild via the task tool, the
|
||||
// protocol's subagent_task_id field carries the parent task_id for
|
||||
// routing, not the new child task_id. We must update it to the
|
||||
// child's task_id from the task_started event so that "查看实时进度"
|
||||
// navigates to the correct (grandchild) session.
|
||||
if (message.type === 'task_started') {
|
||||
const msg = message as TaskStarted
|
||||
if (msg.parent_task_id === currentSubAgentView.taskId) {
|
||||
setSubAgentStack((prev) => {
|
||||
if (prev.length === 0) return prev
|
||||
const top = prev[prev.length - 1]
|
||||
const updatedMessages = [...top.messages]
|
||||
for (let i = updatedMessages.length - 1; i >= 0; i--) {
|
||||
const m = updatedMessages[i]
|
||||
if (m.type === 'tool_call' && m.toolName === 'task' && m.subagentTaskId === currentSubAgentView.taskId) {
|
||||
updatedMessages[i] = { ...m, subagentTaskId: msg.task_id }
|
||||
break
|
||||
}
|
||||
}
|
||||
const newStack = [...prev]
|
||||
newStack[newStack.length - 1] = { ...top, messages: updatedMessages }
|
||||
return newStack
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user