command_manager.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. from typing import List
  2. from opendevin import config
  3. from opendevin.observation import CmdOutputObservation
  4. from opendevin.sandbox import DockerExecBox, DockerSSHBox, Sandbox
  5. from opendevin.schema import ConfigType
  6. class CommandManager:
  7. id: str
  8. directory: str
  9. shell: Sandbox
  10. def __init__(
  11. self,
  12. sid: str,
  13. directory: str,
  14. container_image: str | None = None,
  15. ):
  16. self.directory = directory
  17. if config.get(ConfigType.SANDBOX_TYPE).lower() == 'exec':
  18. self.shell = DockerExecBox(
  19. sid=(sid or 'default'), workspace_dir=directory, container_image=container_image
  20. )
  21. else:
  22. self.shell = DockerSSHBox(
  23. sid=(sid or 'default'), workspace_dir=directory, container_image=container_image
  24. )
  25. def run_command(self, command: str, background=False) -> CmdOutputObservation:
  26. if background:
  27. return self._run_background(command)
  28. else:
  29. return self._run_immediately(command)
  30. def _run_immediately(self, command: str) -> CmdOutputObservation:
  31. exit_code, output = self.shell.execute(command)
  32. return CmdOutputObservation(
  33. command_id=-1, content=output, command=command, exit_code=exit_code
  34. )
  35. def _run_background(self, command: str) -> CmdOutputObservation:
  36. bg_cmd = self.shell.execute_in_background(command)
  37. # FIXME: autopep8 and mypy are fighting each other on this line
  38. # autopep8: off
  39. content = f'Background command started. To stop it, send a `kill` action with id {bg_cmd.id}'
  40. return CmdOutputObservation(
  41. content=content,
  42. command_id=bg_cmd.id,
  43. command=command,
  44. exit_code=0,
  45. )
  46. def kill_command(self, id: int) -> CmdOutputObservation:
  47. cmd = self.shell.kill_background(id)
  48. return CmdOutputObservation(
  49. content=f'Background command with id {id} has been killed.',
  50. command_id=id,
  51. command=cmd.command,
  52. exit_code=0,
  53. )
  54. def get_background_obs(self) -> List[CmdOutputObservation]:
  55. obs = []
  56. for _id, cmd in self.shell.background_commands.items():
  57. output = cmd.read_logs()
  58. if output is not None and output != '':
  59. obs.append(
  60. CmdOutputObservation(
  61. content=output, command_id=_id, command=cmd.command
  62. )
  63. )
  64. return obs