diff --git a/src/bus/message.rs b/src/bus/message.rs index d4d2d21..bfadaab 100644 --- a/src/bus/message.rs +++ b/src/bus/message.rs @@ -571,7 +571,8 @@ impl OutboundMessage { "assistant" => { if let Some(tool_calls) = &message.tool_calls { let mut outbound = Vec::new(); - if !message.content.trim().is_empty() { + let has_content_or_reasoning = !message.content.trim().is_empty() || message.reasoning_content.is_some(); + if has_content_or_reasoning { let mut resp = Self::assistant( channel.to_string(), chat_id.to_string(), @@ -585,7 +586,7 @@ impl OutboundMessage { } outbound.extend(tool_calls.iter().map(|tool_call| { - Self::tool_call( + let mut tc = Self::tool_call( channel.to_string(), chat_id.to_string(), session_id.clone(), @@ -594,7 +595,9 @@ impl OutboundMessage { tool_call.arguments.clone(), reply_to.clone(), metadata.clone(), - ) + ); + tc.reasoning_content = message.reasoning_content.clone(); + tc })); outbound } else { diff --git a/src/gateway/ws.rs b/src/gateway/ws.rs index 1cacf97..8bc479f 100644 --- a/src/gateway/ws.rs +++ b/src/gateway/ws.rs @@ -762,6 +762,7 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option, #[serde(default, skip_serializing_if = "Option::is_none")] timestamp: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + reasoning_content: Option, }, #[serde(rename = "tool_result")] ToolResult { diff --git a/src/protocol/ws_adapter.rs b/src/protocol/ws_adapter.rs index a9d5e1d..42c0080 100644 --- a/src/protocol/ws_adapter.rs +++ b/src/protocol/ws_adapter.rs @@ -15,7 +15,8 @@ pub(crate) fn ws_outbound_from_chat_message(message: &ChatMessage) -> Vec { if let Some(tool_calls) = &message.tool_calls { let mut outbound = Vec::new(); - if !message.content.trim().is_empty() { + let has_content_or_reasoning = !message.content.trim().is_empty() || message.reasoning_content.is_some(); + if has_content_or_reasoning { outbound.push(WsOutbound::AssistantResponse { id: message.id.clone(), content: message.content.clone(), @@ -38,6 +39,7 @@ pub(crate) fn ws_outbound_from_chat_message(message: &ChatMessage) -> Vec Ve subagent_task_id: message.metadata.get("subagent_task_id").cloned(), topic_id: message.metadata.get("topic_id").cloned(), timestamp: Some(crate::protocol::now_timestamp()), + reasoning_content: message.reasoning_content.clone(), }], OutboundEventKind::ToolResult => vec![WsOutbound::ToolResult { id: message diff --git a/tests/test_request_format.rs b/tests/test_request_format.rs index 0c39a14..8e41f49 100644 --- a/tests/test_request_format.rs +++ b/tests/test_request_format.rs @@ -125,6 +125,7 @@ fn test_tool_call_outbound_serialization() { subagent_task_id: None, topic_id: None, timestamp: None, + reasoning_content: None, }; let json = serde_json::to_string(&msg).unwrap(); diff --git a/web/src/components/Chat/MessageBubble.tsx b/web/src/components/Chat/MessageBubble.tsx index f347af9..68e11a8 100644 --- a/web/src/components/Chat/MessageBubble.tsx +++ b/web/src/components/Chat/MessageBubble.tsx @@ -242,11 +242,11 @@ function ThinkingSection({ content }: { content: string }) { return (
{expanded && (
-
+
{content}
@@ -437,6 +437,12 @@ export function MessageBubble({ message, onNavigateToSubAgent }: MessageBubblePr
+ {/* 模型思考内容(工具调用时展示) */} + {message.reasoningContent && !toolExpanded && ( +
+ +
+ )} {/* Collapsed preview */} {!toolExpanded && ( <> @@ -495,6 +501,10 @@ export function MessageBubble({ message, onNavigateToSubAgent }: MessageBubblePr {/* Expanded */} {toolExpanded && (
+ {/* 模型思考内容(展开时也展示) */} + {message.reasoningContent && ( + + )} {taskResult ? ( <> {taskPrompt && ( @@ -646,7 +656,7 @@ export function MessageBubble({ message, onNavigateToSubAgent }: MessageBubblePr {!isTool && message.reasoningContent && ( )} - // AI 和工具消息使用 Markdown 渲染 + {/* AI 和工具消息使用 Markdown 渲染 */}