Compare commits

...

3 Commits

3 changed files with 52 additions and 30 deletions

View File

@ -103,7 +103,8 @@
- 在信息不足时先补关键前提,在信息充分时直接执行。 - 在信息不足时先补关键前提,在信息充分时直接执行。
- Skill 不是工具名。看到可用 Skill 时,不能直接调用 Skill 名称;必须先调用 skill_activate并传入对应的 name。 - Skill 不是工具名。看到可用 Skill 时,不能直接调用 Skill 名称;必须先调用 skill_activate并传入对应的 name。
- 调用工具的时候必须同时用简短的话告诉用户你调用工具是做什么 - 调用工具的时候必须同时用简短的话告诉用户你调用工具是做什么
- 无需担心创建子智能体过多的问题请按用户或者skill的要求创建对应数量的子智能体这样可以隔离上下文更好完成工作
- 思考的时候建议用中文思考
## 定时任务 ## 定时任务

View File

@ -636,8 +636,7 @@ async fn send_topic_history(
// 将消息转换为 WsOutbound 并发送 // 将消息转换为 WsOutbound 并发送
for msg in messages { for msg in messages {
let outbound = chat_message_to_ws_outbound(&msg); for outbound in chat_message_to_ws_outbound(&msg) {
if let Some(outbound) = outbound {
let _ = sender.send(outbound).await; let _ = sender.send(outbound).await;
} }
} }
@ -657,13 +656,13 @@ async fn send_task_messages(
tracing::info!(session_id = %session_id, message_count = messages.len(), "Sending task messages"); tracing::info!(session_id = %session_id, message_count = messages.len(), "Sending task messages");
for msg in messages { for msg in messages {
let mut outbound = chat_message_to_ws_outbound(&msg); let mut outbounds = chat_message_to_ws_outbound(&msg);
if let Some(ref task_id) = subagent_task_id { if let Some(ref task_id) = subagent_task_id {
if let Some(ref mut ob) = outbound { for ob in &mut outbounds {
set_subagent_task_id(ob, task_id); set_subagent_task_id(ob, task_id);
} }
} }
if let Some(outbound) = outbound { for outbound in outbounds {
let _ = sender.send(outbound).await; let _ = sender.send(outbound).await;
} }
} }
@ -692,8 +691,8 @@ fn set_subagent_task_id(outbound: &mut WsOutbound, task_id: &str) {
} }
} }
/// 将 ChatMessage 转换为 WsOutbound /// 将 ChatMessage 转换为 WsOutbound 列表
fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbound> { fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Vec<WsOutbound> {
use crate::bus::message::ToolMessageState; use crate::bus::message::ToolMessageState;
// Helper function to strip media_refs_json from content // Helper function to strip media_refs_json from content
@ -750,9 +749,24 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
match msg.role.as_str() { match msg.role.as_str() {
"assistant" => { "assistant" => {
if let Some(tool_calls) = &msg.tool_calls { if let Some(tool_calls) = &msg.tool_calls {
// 如果有 tool_calls发送 ToolCall 消息 let mut outbound = Vec::new();
if let Some(tool_call) = tool_calls.first() { let has_content_or_reasoning = !msg.content.trim().is_empty() || msg.reasoning_content.is_some();
return Some(WsOutbound::ToolCall { if has_content_or_reasoning {
outbound.push(WsOutbound::AssistantResponse {
id: msg.id.clone(),
content: msg.content.clone(),
role: msg.role.clone(),
attachments: Vec::new(),
subagent_task_id: None,
topic_id: None,
timestamp: Some(msg.timestamp / 1000),
reasoning_content: msg.reasoning_content.clone(),
});
}
// AssistantResponse 已携带 reasoning 时ToolCall 不再重复
let tc_reasoning = if has_content_or_reasoning { None } else { msg.reasoning_content.clone() };
for tool_call in tool_calls {
outbound.push(WsOutbound::ToolCall {
id: msg.id.clone(), id: msg.id.clone(),
tool_call_id: tool_call.id.clone(), tool_call_id: tool_call.id.clone(),
tool_name: tool_call.name.clone(), tool_name: tool_call.name.clone(),
@ -762,12 +776,13 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
subagent_task_id: None, subagent_task_id: None,
topic_id: None, topic_id: None,
timestamp: Some(msg.timestamp / 1000), timestamp: Some(msg.timestamp / 1000),
reasoning_content: msg.reasoning_content.clone(), reasoning_content: tc_reasoning.clone(),
}); });
} }
} outbound
} else {
// 普通助手消息 // 普通助手消息
Some(WsOutbound::AssistantResponse { vec![WsOutbound::AssistantResponse {
id: msg.id.clone(), id: msg.id.clone(),
content: msg.content.clone(), content: msg.content.clone(),
role: msg.role.clone(), role: msg.role.clone(),
@ -776,12 +791,13 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
topic_id: None, topic_id: None,
timestamp: Some(msg.timestamp / 1000), timestamp: Some(msg.timestamp / 1000),
reasoning_content: msg.reasoning_content.clone(), reasoning_content: msg.reasoning_content.clone(),
}) }]
}
} }
"tool" => { "tool" => {
let tool_state = msg.tool_state.as_ref().unwrap_or(&ToolMessageState::Completed); let tool_state = msg.tool_state.as_ref().unwrap_or(&ToolMessageState::Completed);
match tool_state { match tool_state {
ToolMessageState::Completed => Some(WsOutbound::ToolResult { ToolMessageState::Completed => vec![WsOutbound::ToolResult {
id: msg.id.clone(), id: msg.id.clone(),
tool_call_id: msg.tool_call_id.clone().unwrap_or_default(), tool_call_id: msg.tool_call_id.clone().unwrap_or_default(),
tool_name: msg.tool_name.clone().unwrap_or_default(), tool_name: msg.tool_name.clone().unwrap_or_default(),
@ -791,8 +807,8 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
topic_id: None, topic_id: None,
duration_ms: msg.tool_duration_ms, duration_ms: msg.tool_duration_ms,
timestamp: Some(msg.timestamp / 1000), timestamp: Some(msg.timestamp / 1000),
}), }],
ToolMessageState::PendingUserAction => Some(WsOutbound::ToolPending { ToolMessageState::PendingUserAction => vec![WsOutbound::ToolPending {
id: msg.id.clone(), id: msg.id.clone(),
tool_call_id: msg.tool_call_id.clone().unwrap_or_default(), tool_call_id: msg.tool_call_id.clone().unwrap_or_default(),
tool_name: msg.tool_name.clone().unwrap_or_default(), tool_name: msg.tool_name.clone().unwrap_or_default(),
@ -802,10 +818,10 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
subagent_task_id: None, subagent_task_id: None,
topic_id: None, topic_id: None,
timestamp: Some(msg.timestamp / 1000), timestamp: Some(msg.timestamp / 1000),
}), }],
} }
} }
"user" => Some(WsOutbound::AssistantResponse { "user" => vec![WsOutbound::AssistantResponse {
id: msg.id.clone(), id: msg.id.clone(),
content: strip_media_refs_json(&msg.content), content: strip_media_refs_json(&msg.content),
role: msg.role.clone(), role: msg.role.clone(),
@ -814,8 +830,8 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
topic_id: None, topic_id: None,
timestamp: Some(msg.timestamp / 1000), timestamp: Some(msg.timestamp / 1000),
reasoning_content: None, reasoning_content: None,
}), }],
_ => None, _ => Vec::new(),
} }
} }

View File

@ -589,6 +589,11 @@ export function MessageBubble({ message, onNavigateToSubAgent, showThinking = tr
) )
} }
// 隐藏思考且无实质内容时,不渲染空的助手消息气泡
if (!isUser && !isTool && !isMergedTool && !showThinking && !message.content.trim() && message.reasoningContent) {
return null
}
const getIcon = () => { const getIcon = () => {
if (isUser) return <User className="h-4 w-4" /> if (isUser) return <User className="h-4 w-4" />
if (isTool) { if (isTool) {