From 8a85e9025e183e80c4370d4251ca0d5af6203a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E6=BD=AE?= Date: Wed, 7 Jan 2026 19:24:28 +0800 Subject: [PATCH] fix(sse): properly handle MCP tool errors and send error responses to client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enhance exception handling in agent_task() to capture and send structured error messages via SSE stream - Add [DONE] marker to outer exception handler to ensure proper stream termination - Improve MCP tool loading error handling in init_agent() to prevent cascading failures - Add detailed error logging with traceback for debugging Fixes RemoteProtocolError that occurred when MCP tool calls failed, which previously caused incomplete chunked read errors and connection drops. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- agent/deep_assistant.py | 12 ++++++++++-- routes/chat.py | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/agent/deep_assistant.py b/agent/deep_assistant.py index 7d9c2b8..e51bdde 100644 --- a/agent/deep_assistant.py +++ b/agent/deep_assistant.py @@ -102,8 +102,11 @@ async def get_tools_from_mcp(mcp): logger.info(f"get_tools_from_mcp: loaded {len(mcp_tools)} tools, elapsed: {time.time() - start_time:.3f}s") return mcp_tools except Exception as e: + import traceback + error_details = traceback.format_exc() # 发生异常时返回空列表,避免上层调用报错 - logger.info(f"get_tools_from_mcp: error {e}, elapsed: {time.time() - start_time:.3f}s") + logger.error(f"get_tools_from_mcp: error {str(e)}, elapsed: {time.time() - start_time:.3f}s") + logger.error(f"Full traceback: {error_details}") return [] async def init_agent(config: AgentConfig): @@ -139,7 +142,12 @@ async def init_agent(config: AgentConfig): config.mcp_settings = system_prompt # 获取 mcp_tools(缓存逻辑已内置到 get_tools_from_mcp 中) - mcp_tools = await get_tools_from_mcp(mcp_settings) + try: + mcp_tools = await get_tools_from_mcp(mcp_settings) + logger.info(f"Successfully loaded {len(mcp_tools)} MCP tools") + except Exception as e: + logger.error(f"Failed to load MCP tools: {str(e)}, using empty tool list") + mcp_tools = [] # 检测或使用指定的提供商 model_provider, base_url = detect_provider(config.model_name, config.model_server) diff --git a/routes/chat.py b/routes/chat.py index 0d67f60..7e80bd5 100644 --- a/routes/chat.py +++ b/routes/chat.py @@ -114,7 +114,22 @@ async def enhanced_generate_stream_response( await output_queue.put(("agent_done", None)) except Exception as e: - logger.error(f"Error in agent task: {e}") + import traceback + error_details = traceback.format_exc() + logger.error(f"Error in agent task: {str(e)}") + logger.error(f"Full traceback: {error_details}") + + # 发送错误信息给客户端 + error_data = { + "error": { + "message": f"Agent execution failed: {str(e)}", + "type": "agent_error", + "details": error_details if __debug__ else str(e) + } + } + error_chunk = create_stream_chunk(f"chatcmpl-error", config.model_name, json.dumps(error_data, ensure_ascii=False)) + await output_queue.put(("agent", f"data: {json.dumps(error_chunk, ensure_ascii=False)}\n\n")) + # 发送完成信号,确保输出控制器能正常结束 await output_queue.put(("agent_done", None)) # 并发执行任务 @@ -186,6 +201,7 @@ async def enhanced_generate_stream_response( } } yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n" + yield "data: [DONE]\n\n" async def create_agent_and_generate_response(