fix: 修复智能体调用卡死问题
- 添加--json参数到openclaw agent命令 - 正确解析JSON输出结构: result.payloads[0].text - 使用Popen替代subprocess.run,支持进程组杀死 - 超时时间从5分钟改为3分钟 - 添加os.setsid创建新进程组,确保超时时能杀死所有子进程 - 增强异常处理和日志记录
This commit is contained in:
+48
-16
@@ -341,6 +341,9 @@ class ProcessMonitor:
|
||||
except Exception as e:
|
||||
logger.error(f"处理会话异常: {session_id} - {e}")
|
||||
db.update_session_status(session_id, 'failed')
|
||||
# 确保清理
|
||||
if session_id in self.active_sessions:
|
||||
del self.active_sessions[session_id]
|
||||
return {'success': False, 'message': str(e)}
|
||||
|
||||
def _start_step(self, session_id, product_name, step_num, step_name):
|
||||
@@ -466,36 +469,65 @@ class ProcessMonitor:
|
||||
|
||||
def _call_agent(self, task_text):
|
||||
"""调用智能体执行任务"""
|
||||
import signal
|
||||
|
||||
try:
|
||||
cmd = [
|
||||
'openclaw', 'agent',
|
||||
'--agent', 'hz4th_editor',
|
||||
'--message', task_text
|
||||
'--message', task_text,
|
||||
'--json' # 输出JSON格式以便解析
|
||||
]
|
||||
|
||||
logger.info(f"调用智能体命令: openclaw agent --agent hz4th_editor --message '[任务文本 {len(task_text)} 字符]'")
|
||||
logger.info(f"调用智能体命令: openclaw agent --agent hz4th_editor --message '[任务文本 {len(task_text)} 字符]' --json")
|
||||
|
||||
result = subprocess.run(
|
||||
# 使用Popen以便更好地控制超时和进程杀死
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=300 # 5分钟超时
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
preexec_fn=os.setsid # 创建新进程组,方便杀死所有子进程
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
output = result.stdout.strip()
|
||||
logger.info(f"智能体返回: {output[:500]}...")
|
||||
return {'success': True, 'output': output}
|
||||
else:
|
||||
error = result.stderr.strip() or result.stdout.strip()
|
||||
logger.error(f"智能体调用失败: {error}")
|
||||
return {'success': False, 'error': error}
|
||||
try:
|
||||
stdout, stderr = proc.communicate(timeout=180) # 3分钟超时
|
||||
raw_output = stdout.decode('utf-8', errors='replace').strip()
|
||||
|
||||
if proc.returncode == 0:
|
||||
# 解析JSON输出
|
||||
try:
|
||||
data = json.loads(raw_output)
|
||||
# 提取实际回复文本: result.payloads[0].text
|
||||
payloads = data.get('result', {}).get('payloads', [])
|
||||
if payloads and isinstance(payloads[0], dict):
|
||||
output = payloads[0].get('text', '')
|
||||
else:
|
||||
output = raw_output
|
||||
|
||||
logger.info(f"智能体返回: {output[:500]}...")
|
||||
return {'success': True, 'output': output}
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warning(f"JSON解析失败,使用原始输出: {e}")
|
||||
return {'success': True, 'output': raw_output}
|
||||
else:
|
||||
error = stderr.decode('utf-8', errors='replace').strip() or raw_output
|
||||
logger.error(f"智能体调用失败(returncode={proc.returncode}): {error}")
|
||||
return {'success': False, 'error': error}
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
# 超时,杀死整个进程组
|
||||
logger.error(f"智能体执行超时(>3分钟),杀死进程组")
|
||||
try:
|
||||
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
|
||||
except Exception:
|
||||
proc.kill()
|
||||
proc.wait()
|
||||
return {'success': False, 'error': '智能体执行超时(>3分钟)'}
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
return {'success': False, 'error': '智能体执行超时(>5分钟)'}
|
||||
except FileNotFoundError:
|
||||
return {'success': False, 'error': 'openclaw命令未找到'}
|
||||
except Exception as e:
|
||||
logger.error(f"智能体调用异常: {e}")
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
def _parse_agent_response(self, output):
|
||||
|
||||
Reference in New Issue
Block a user