mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-05-22 03:06:54 +00:00
fix(code_execution): handle closed PTYs while reading output
This commit is contained in:
parent
d4eaa7c030
commit
eecbb5ba34
2 changed files with 48 additions and 11 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import asyncio
|
||||
import errno
|
||||
from dataclasses import dataclass
|
||||
import re
|
||||
import shlex
|
||||
|
|
@ -15,6 +16,17 @@ from plugins._code_execution.helpers.shell_local import LocalInteractiveSession
|
|||
from plugins._code_execution.helpers.shell_ssh import SSHInteractiveSession
|
||||
|
||||
|
||||
def _is_closed_pty_error(exc: BaseException) -> bool:
|
||||
if isinstance(exc, RuntimeError) and "TTYSpawn PTY is closed" in str(exc):
|
||||
return True
|
||||
if isinstance(exc, OSError) and exc.errno in (errno.EBADF, errno.EIO, errno.EINVAL):
|
||||
return True
|
||||
cause = getattr(exc, "__cause__", None)
|
||||
if cause and cause is not exc:
|
||||
return _is_closed_pty_error(cause)
|
||||
return False
|
||||
|
||||
|
||||
@dataclass
|
||||
class ShellWrap:
|
||||
id: int
|
||||
|
|
@ -194,11 +206,12 @@ class CodeExecution(Tool):
|
|||
)
|
||||
|
||||
except Exception as e:
|
||||
PrintStyle.error(str(e))
|
||||
await self.prepare_state(cfg, reset=True, session=session)
|
||||
if i == 0:
|
||||
if _is_closed_pty_error(e) and i == 0:
|
||||
PrintStyle.warning(f"Terminal session {session} was closed; resetting and retrying once.")
|
||||
await self.prepare_state(cfg, reset=True, session=session)
|
||||
continue
|
||||
raise e
|
||||
PrintStyle.error(str(e))
|
||||
raise
|
||||
|
||||
def format_command_for_output(self, command: str):
|
||||
short_cmd = command[:250]
|
||||
|
|
@ -244,9 +257,19 @@ class CodeExecution(Tool):
|
|||
|
||||
while True:
|
||||
await asyncio.sleep(sleep_time)
|
||||
full_output, partial_output = await self.state.shells[session].session.read_output(
|
||||
timeout=1, reset_full_output=reset_full_output
|
||||
)
|
||||
try:
|
||||
full_output, partial_output = await self.state.shells[session].session.read_output(
|
||||
timeout=1, reset_full_output=reset_full_output
|
||||
)
|
||||
except Exception as e:
|
||||
if _is_closed_pty_error(e):
|
||||
await self.prepare_state(cfg, reset=True, session=session)
|
||||
self.mark_session_idle(session)
|
||||
sysinfo = "Terminal session was closed and has been reset. Please run the command again."
|
||||
response = self.agent.read_prompt("fw.code.info.md", info=sysinfo)
|
||||
self.log.update(content=prefix + response)
|
||||
return response
|
||||
raise
|
||||
reset_full_output = False # only reset once
|
||||
|
||||
await self.agent.handle_intervention()
|
||||
|
|
@ -363,9 +386,16 @@ class CodeExecution(Tool):
|
|||
prompt_patterns = cfg["prompt_patterns"]
|
||||
dialog_patterns = cfg["dialog_patterns"]
|
||||
|
||||
full_output, _ = await self.state.shells[session].session.read_output(
|
||||
timeout=1, reset_full_output=reset_full_output
|
||||
)
|
||||
try:
|
||||
full_output, _ = await self.state.shells[session].session.read_output(
|
||||
timeout=1, reset_full_output=reset_full_output
|
||||
)
|
||||
except Exception as e:
|
||||
if _is_closed_pty_error(e):
|
||||
await self.prepare_state(cfg, reset=True, session=session)
|
||||
self.mark_session_idle(session)
|
||||
return None
|
||||
raise
|
||||
truncated_output = self.fix_full_output(full_output)
|
||||
self.set_progress(truncated_output)
|
||||
heading = self.get_heading_from_output(truncated_output, 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue