command_manager.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. from typing import List
  2. from opendevin.lib.event import Event
  3. from opendevin.sandbox.sandbox import DockerInteractive
  4. class BackgroundCommand:
  5. def __init__(self, id: int, command: str, dir: str):
  6. self.command = command
  7. self.id = id
  8. self.shell = DockerInteractive(id=str(id), workspace_dir=dir)
  9. self.shell.execute_in_background(command)
  10. def get_logs(self):
  11. # TODO: get an exit code if process is exited
  12. return self.shell.read_logs()
  13. class CommandManager:
  14. def __init__(self, dir):
  15. self.cur_id = 0
  16. self.directory = dir
  17. self.background_commands = {}
  18. self.shell = DockerInteractive(id="default", workspace_dir=dir)
  19. def run_command(self, command: str, background=False) -> str:
  20. if background:
  21. return self.run_background(command)
  22. else:
  23. return self.run_immediately(command)
  24. def run_immediately(self, command: str) -> str:
  25. exit_code, output = self.shell.execute(command)
  26. if exit_code != 0:
  27. raise ValueError('Command failed with exit code ' + str(exit_code) + ': ' + output)
  28. return output
  29. def run_background(self, command: str) -> str:
  30. bg_cmd = BackgroundCommand(self.cur_id, command, self.directory)
  31. self.cur_id += 1
  32. self.background_commands[bg_cmd.id] = bg_cmd
  33. return "Background command started. To stop it, send a `kill` action with id " + str(bg_cmd.id)
  34. def kill_command(self, id: int):
  35. # TODO: get log events before killing
  36. self.background_commands[id].shell.close()
  37. del self.background_commands[id]
  38. def get_background_events(self) -> List[Event]:
  39. events = []
  40. for id, cmd in self.background_commands.items():
  41. output = cmd.get_logs()
  42. events.append(Event('output', {
  43. 'output': output,
  44. 'id': id,
  45. 'command': cmd.command,
  46. }))
  47. return events