From 9c41adc6e2529bd01a4600b59fac342f4c25ae7b Mon Sep 17 00:00:00 2001 From: Hongyu Shi Date: Tue, 12 Aug 2025 19:22:56 +0800 Subject: [PATCH 1/2] feat(mcp): fix mcp ux message Signed-off-by: Hongyu Shi --- src/backend/hermes/mcp_helpers.py | 15 ++++++--- src/backend/hermes/stream.py | 51 +++++++++++-------------------- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/backend/hermes/mcp_helpers.py b/src/backend/hermes/mcp_helpers.py index 6464195..383da8d 100644 --- a/src/backend/hermes/mcp_helpers.py +++ b/src/backend/hermes/mcp_helpers.py @@ -142,6 +142,8 @@ class MCPIndicators: MCPEmojis.OUTPUT, MCPEmojis.CANCEL, MCPEmojis.ERROR, + MCPEmojis.WAITING_START, + MCPEmojis.WAITING_PARAM, ] @@ -231,12 +233,17 @@ def is_final_mcp_message(content: str) -> bool: def is_progress_message(content: str) -> bool: """检查内容是否为进度状态消息""" - # 检查是否包含进度表情符号 - if any(emoji in content for emoji in MCPIndicators.PROGRESS_INDICATORS): + # 首先检查是否包含 MCP 或 REPLACE 标记 + if MCPTags.MCP_PREFIX in content or MCPTags.REPLACE_PREFIX in content: + return True + + # 检查是否包含明确的 MCP 状态指示符(更严格的匹配) + if any(indicator in content for indicator in MCPIndicators.ALL_INDICATORS): return True - # 检查是否包含 MCP 或 REPLACE 标记 - return MCPTags.MCP_PREFIX in content or MCPTags.REPLACE_PREFIX in content + # 检查是否为标准的工具状态消息格式:表情符号 + "工具" + 工具名称 + tool_message_pattern = r"[🔧📥✅❌⚠️⏸️📝]\s*(工具\s*`[^`]+`|正在初始化工具|\*\*等待用户[^*]*\*\*)" + return bool(re.search(tool_message_pattern, content)) def classify_mcp_message(content: str) -> str: diff --git a/src/backend/hermes/stream.py b/src/backend/hermes/stream.py index 191af6c..b45fc99 100644 --- a/src/backend/hermes/stream.py +++ b/src/backend/hermes/stream.py @@ -169,10 +169,24 @@ class HermesStreamProcessor: # 处理特殊的等待状态事件 if event_type == "step.waiting_for_start": - return self._format_waiting_for_start(content, step_name, step_id, should_replace=should_replace) + base_message = self._format_waiting_for_start(content, step_name) + return self._handle_progress_message( + event_type, + step_name, + step_id, + base_message, + should_replace=should_replace, + ) if event_type == "step.waiting_for_param": - return self._format_waiting_for_param(content, step_name, step_id, should_replace=should_replace) + base_message = self._format_waiting_for_param(content, step_name) + return self._handle_progress_message( + event_type, + step_name, + step_id, + base_message, + should_replace=should_replace, + ) # 处理其他事件类型 return self._format_standard_status(event_type, step_name, step_id, should_replace=should_replace) @@ -181,50 +195,21 @@ class HermesStreamProcessor: self, content: dict[str, Any], step_name: str, - step_id: str, - *, - should_replace: bool, ) -> str: """格式化等待开始执行的消息""" risk = content.get("risk", MCPRiskLevels.UNKNOWN) reason = content.get("reason", "需要用户确认是否执行此工具") - - # 使用统一的风险级别显示 risk_info = MCPRiskLevels.get_risk_display(risk) - - message = MCPMessageTemplates.waiting_start_message(step_name, risk_info, reason) - - # 记录进度信息 - if step_id: - self._current_tool_progress[step_id] = { - "message": message, - "should_replace": should_replace, - "is_progress": True, - } - - return message + return MCPMessageTemplates.waiting_start_message(step_name, risk_info, reason) def _format_waiting_for_param( self, content: dict[str, Any], step_name: str, - step_id: str, - *, - should_replace: bool, ) -> str: """格式化等待参数输入的消息""" message_content = content.get("message", "需要补充参数") - message = MCPMessageTemplates.waiting_param_message(step_name, message_content) - - # 记录进度信息 - if step_id: - self._current_tool_progress[step_id] = { - "message": message, - "should_replace": should_replace, - "is_progress": True, - } - - return message + return MCPMessageTemplates.waiting_param_message(step_name, message_content) def _format_standard_status( self, -- Gitee From d5d62bcdce6f1c2236c907d24f86253e13b404d5 Mon Sep 17 00:00:00 2001 From: Hongyu Shi Date: Tue, 12 Aug 2025 20:36:22 +0800 Subject: [PATCH 2/2] chore: clean code Signed-off-by: Hongyu Shi --- src/app/tui.py | 14 +++------- src/backend/hermes/mcp_helpers.py | 43 ------------------------------- 2 files changed, 3 insertions(+), 54 deletions(-) diff --git a/src/app/tui.py b/src/app/tui.py index 427b18c..d3ffccf 100644 --- a/src/app/tui.py +++ b/src/app/tui.py @@ -25,7 +25,7 @@ from backend.hermes.mcp_helpers import ( extract_mcp_tag, format_error_message, is_final_mcp_message, - is_progress_message, + is_mcp_message, ) from config import ConfigManager from log.manager import get_logger, log_exception @@ -668,7 +668,7 @@ class IntelligentTerminal(App): # 检查是否为 MCP 进度消息 tool_name = replace_tool_name or mcp_tool_name - is_progress_message = tool_name is not None and self._is_progress_message(cleaned_content) + is_progress_message = tool_name is not None and is_mcp_message(content) # 如果是进度消息,使用专门的处理方法,无论 is_llm_output 的值 if is_progress_message and tool_name: @@ -721,7 +721,7 @@ class IntelligentTerminal(App): ) -> None: """处理 MCP 进度消息""" # 检查是否为最终状态消息 - is_final_message = self._is_final_progress_message(content) + is_final_message = is_final_mcp_message(content) # 检查是否有现有的进度消息 existing_progress = self._current_progress_lines.get(tool_name) @@ -762,14 +762,6 @@ class IntelligentTerminal(App): output_container.mount(new_progress_line) self.logger.debug("创建工具 %s 的新进度消息: %s", tool_name, content.strip()[:50]) - def _is_progress_message(self, content: str) -> bool: - """判断是否为进度消息""" - return is_progress_message(content) - - def _is_final_progress_message(self, content: str) -> bool: - """判断是否为最终进度消息(执行完成、失败、取消等)""" - return is_final_mcp_message(content) - def _format_error_message(self, error: BaseException) -> str: """格式化错误消息""" error_str = str(error).lower() diff --git a/src/backend/hermes/mcp_helpers.py b/src/backend/hermes/mcp_helpers.py index 383da8d..e755349 100644 --- a/src/backend/hermes/mcp_helpers.py +++ b/src/backend/hermes/mcp_helpers.py @@ -204,17 +204,6 @@ class MCPRiskLevels: return cls.RISK_DISPLAY_MAP.get(risk_level, cls.RISK_DISPLAY_MAP[cls.UNKNOWN]) -# MCP 消息类型枚举 -class MCPMessageType: - """MCP 消息类型常量""" - - NORMAL = "normal" # 普通消息 - MCP_TAGGED = "mcp_tagged" # 带有 [MCP:] 标记的消息 - REPLACE_TAGGED = "replace_tagged" # 带有 [REPLACE:] 标记的消息 - PROGRESS = "progress" # 进度状态消息 - FINAL = "final" # 最终状态消息 - - # 工具函数 def is_mcp_message(content: str) -> bool: """检查内容是否为 MCP 状态消息""" @@ -231,38 +220,6 @@ def is_final_mcp_message(content: str) -> bool: return any(indicator in content for indicator in MCPIndicators.FINAL_INDICATORS) -def is_progress_message(content: str) -> bool: - """检查内容是否为进度状态消息""" - # 首先检查是否包含 MCP 或 REPLACE 标记 - if MCPTags.MCP_PREFIX in content or MCPTags.REPLACE_PREFIX in content: - return True - - # 检查是否包含明确的 MCP 状态指示符(更严格的匹配) - if any(indicator in content for indicator in MCPIndicators.ALL_INDICATORS): - return True - - # 检查是否为标准的工具状态消息格式:表情符号 + "工具" + 工具名称 - tool_message_pattern = r"[🔧📥✅❌⚠️⏸️📝]\s*(工具\s*`[^`]+`|正在初始化工具|\*\*等待用户[^*]*\*\*)" - return bool(re.search(tool_message_pattern, content)) - - -def classify_mcp_message(content: str) -> str: - """分类 MCP 消息类型""" - if MCPTags.REPLACE_PREFIX in content: - return MCPMessageType.REPLACE_TAGGED - - if MCPTags.MCP_PREFIX in content: - return MCPMessageType.MCP_TAGGED - - if is_final_mcp_message(content): - return MCPMessageType.FINAL - - if is_progress_message(content): - return MCPMessageType.PROGRESS - - return MCPMessageType.NORMAL - - def extract_mcp_tag(content: str) -> tuple[str | None, str]: """从内容中提取 MCP 标记并返回清理后的内容""" # 构建 REPLACE 标记的正则表达式 -- Gitee