refactor(task): 子智能体相关字段重命名及导航逻辑调整
- 将 runtime 中的 sub_session_id 字段重命名为 task_id,作为持久化的 scope_key - 调整持久化 todo_write 结果使用 task_id 代替 session_id 作为 scope_key - 重命名前端消息中的 subagentTaskId 为 navigateToTaskId,增强导航表达 - 修改 MessageBubble 组件中子智能体任务导航相关的字段名和条件判断 - 优化 useChat 中 task tool_call 消息的 navigateToTaskId 设置逻辑,确保正确导航孙智能体任务 - 移除无用的 getTopicId 辅助方法,简化消息处理逻辑 - 在协议类型定义中新增 navigateToTaskId 字段,明确导航用途与关系
This commit is contained in:
parent
e585ec71b1
commit
9ea5849f22
@ -110,7 +110,8 @@ struct SubAgentEmitter {
|
|||||||
chat_id: String,
|
chat_id: String,
|
||||||
metadata: HashMap<String, String>,
|
metadata: HashMap<String, String>,
|
||||||
store: Arc<SessionStore>,
|
store: Arc<SessionStore>,
|
||||||
sub_session_id: String,
|
/// 子/孙智能体自身的 task_id,用于持久化时作为 scope_key
|
||||||
|
task_id: String,
|
||||||
stream_message_id: std::sync::Mutex<Option<String>>,
|
stream_message_id: std::sync::Mutex<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +160,7 @@ impl EmittedMessageHandler for SubAgentEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拦截 todo_write 结果:持久化到 SQLite(子代理用 session_id 作为 scope_key)
|
// 拦截 todo_write 结果:持久化到 SQLite(子代理用 task_id 作为 scope_key,与 list_todos 保持一致)
|
||||||
if message.tool_name.as_deref() == Some("todo_write") {
|
if message.tool_name.as_deref() == Some("todo_write") {
|
||||||
self.persist_todo_write_result(&message);
|
self.persist_todo_write_result(&message);
|
||||||
}
|
}
|
||||||
@ -212,7 +213,7 @@ impl SubAgentEmitter {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let scope_key = &self.sub_session_id;
|
let scope_key = &self.task_id;
|
||||||
|
|
||||||
let now = std::time::SystemTime::now()
|
let now = std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
@ -366,7 +367,7 @@ impl DefaultSubAgentRuntime {
|
|||||||
chat_id: session.parent_chat_id.clone(),
|
chat_id: session.parent_chat_id.clone(),
|
||||||
metadata,
|
metadata,
|
||||||
store: self.store.clone(),
|
store: self.store.clone(),
|
||||||
sub_session_id: session.session_id.clone(),
|
task_id: session.id.clone(),
|
||||||
stream_message_id: std::sync::Mutex::new(None),
|
stream_message_id: std::sync::Mutex::new(None),
|
||||||
},
|
},
|
||||||
self.conversation_repository.clone(),
|
self.conversation_repository.clone(),
|
||||||
|
|||||||
@ -480,12 +480,12 @@ export function MessageBubble({ message, onNavigateToSubAgent, showThinking = tr
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isTaskTool && message.subagentTaskId && !taskResult && (
|
{isTaskTool && message.navigateToTaskId && !taskResult && (
|
||||||
<div className="px-3 pb-1">
|
<div className="px-3 pb-1">
|
||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
onNavigateToSubAgent?.(message.subagentTaskId!, taskDescription || '子智能体任务', subagentType)
|
onNavigateToSubAgent?.(message.navigateToTaskId!, taskDescription || '子智能体任务', subagentType)
|
||||||
}}
|
}}
|
||||||
className="text-xs text-[var(--accent-cyan)] hover:text-[var(--accent-cyan)]/80 hover:underline transition-colors flex items-center gap-1"
|
className="text-xs text-[var(--accent-cyan)] hover:text-[var(--accent-cyan)]/80 hover:underline transition-colors flex items-center gap-1"
|
||||||
>
|
>
|
||||||
@ -494,7 +494,7 @@ export function MessageBubble({ message, onNavigateToSubAgent, showThinking = tr
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isTaskTool && !taskResult && !message.subagentTaskId && (
|
{isTaskTool && !taskResult && !message.navigateToTaskId && (
|
||||||
<div className="px-3 pb-2 text-xs text-[var(--text-muted)]">
|
<div className="px-3 pb-2 text-xs text-[var(--text-muted)]">
|
||||||
子智能体正在执行...
|
子智能体正在执行...
|
||||||
</div>
|
</div>
|
||||||
@ -571,11 +571,11 @@ export function MessageBubble({ message, onNavigateToSubAgent, showThinking = tr
|
|||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isTaskTool && message.subagentTaskId && (
|
{isTaskTool && message.navigateToTaskId && (
|
||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
onNavigateToSubAgent?.(message.subagentTaskId!, taskDescription || '子智能体任务', subagentType)
|
onNavigateToSubAgent?.(message.navigateToTaskId!, taskDescription || '子智能体任务', subagentType)
|
||||||
}}
|
}}
|
||||||
className="text-xs text-[var(--accent-cyan)] hover:text-[var(--accent-cyan)]/80 hover:underline transition-colors flex items-center gap-1"
|
className="text-xs text-[var(--accent-cyan)] hover:text-[var(--accent-cyan)]/80 hover:underline transition-colors flex items-center gap-1"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -206,15 +206,6 @@ export function useChat(): UseChatReturn {
|
|||||||
return undefined
|
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)
|
// Convert a server message to ChatMessage (extracted from handleServerMessage logic)
|
||||||
const serverMessageToChatMessage = (message: WsOutbound): ChatMessage | null => {
|
const serverMessageToChatMessage = (message: WsOutbound): ChatMessage | null => {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
@ -395,12 +386,8 @@ export function useChat(): UseChatReturn {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backfill grandchild task_id on task tool_call in sub-agent view.
|
// When the sub-agent spawns a grandchild, set navigateToTaskId
|
||||||
// When the sub-agent spawns a grandchild via the task tool, the
|
// on the task tool_call so "查看实时进度" navigates correctly.
|
||||||
// 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') {
|
if (message.type === 'task_started') {
|
||||||
const msg = message as TaskStarted
|
const msg = message as TaskStarted
|
||||||
if (msg.parent_task_id === currentSubAgentView.taskId) {
|
if (msg.parent_task_id === currentSubAgentView.taskId) {
|
||||||
@ -410,8 +397,8 @@ export function useChat(): UseChatReturn {
|
|||||||
const updatedMessages = [...top.messages]
|
const updatedMessages = [...top.messages]
|
||||||
for (let i = updatedMessages.length - 1; i >= 0; i--) {
|
for (let i = updatedMessages.length - 1; i >= 0; i--) {
|
||||||
const m = updatedMessages[i]
|
const m = updatedMessages[i]
|
||||||
if (m.type === 'tool_call' && m.toolName === 'task' && m.subagentTaskId === currentSubAgentView.taskId) {
|
if (m.type === 'tool_call' && m.toolName === 'task' && !m.navigateToTaskId) {
|
||||||
updatedMessages[i] = { ...m, subagentTaskId: msg.task_id }
|
updatedMessages[i] = { ...m, navigateToTaskId: msg.task_id }
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -443,23 +430,8 @@ export function useChat(): UseChatReturn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In main view, skip sub-agent messages (they belong to sub-agent view).
|
// 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)
|
const msgSubagentTaskId = getSubagentTaskId(message)
|
||||||
if (msgSubagentTaskId) {
|
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) {
|
|
||||||
const updated = [...prev]
|
|
||||||
updated[i] = { ...updated[i], subagentTaskId: msgSubagentTaskId }
|
|
||||||
return updated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prev
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,12 +450,12 @@ export function useChat(): UseChatReturn {
|
|||||||
// 孙智能体的 TaskStarted 不应 backfill 到主视图
|
// 孙智能体的 TaskStarted 不应 backfill 到主视图
|
||||||
if (msg.parent_task_id) break
|
if (msg.parent_task_id) break
|
||||||
|
|
||||||
// 立即更新对应的 task tool_call,让用户可以点击查看实时进度
|
// 设置 navigateToTaskId,让用户可以点击查看实时进度
|
||||||
setMessages((prev) => {
|
setMessages((prev) => {
|
||||||
for (let i = prev.length - 1; i >= 0; i--) {
|
for (let i = prev.length - 1; i >= 0; i--) {
|
||||||
if (prev[i].type === 'tool_call' && prev[i].toolName === 'task' && !prev[i].subagentTaskId) {
|
if (prev[i].type === 'tool_call' && prev[i].toolName === 'task' && !prev[i].navigateToTaskId) {
|
||||||
const updated = [...prev]
|
const updated = [...prev]
|
||||||
updated[i] = { ...updated[i], subagentTaskId: msg.task_id }
|
updated[i] = { ...updated[i], navigateToTaskId: msg.task_id }
|
||||||
return updated
|
return updated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -453,7 +453,10 @@ export interface ChatMessage {
|
|||||||
status?: 'calling' | 'result' | 'pending'
|
status?: 'calling' | 'result' | 'pending'
|
||||||
resultContent?: string
|
resultContent?: string
|
||||||
callContent?: string
|
callContent?: string
|
||||||
|
/** 路由字段:标识消息属于哪个子智能体会话(与后端 subagent_task_id 一致) */
|
||||||
subagentTaskId?: string
|
subagentTaskId?: string
|
||||||
|
/** 导航字段:仅 task 工具卡片使用,由 task_started 事件设置,指向新创建的子/孙智能体 task_id */
|
||||||
|
navigateToTaskId?: string
|
||||||
durationMs?: number
|
durationMs?: number
|
||||||
reasoningContent?: string
|
reasoningContent?: string
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user