runtime.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import os
  2. import pathlib
  3. from opendevin.core.config import config
  4. from opendevin.events.action import (
  5. AgentRecallAction,
  6. BrowseURLAction,
  7. CmdKillAction,
  8. CmdRunAction,
  9. FileReadAction,
  10. FileWriteAction,
  11. IPythonRunCellAction,
  12. )
  13. from opendevin.events.observation import (
  14. CmdOutputObservation,
  15. ErrorObservation,
  16. IPythonRunCellObservation,
  17. NullObservation,
  18. Observation,
  19. )
  20. from opendevin.runtime.runtime import Runtime
  21. from .browse import browse
  22. from .files import read_file, write_file
  23. class ServerRuntime(Runtime):
  24. async def run(self, action: CmdRunAction) -> Observation:
  25. return self._run_command(action.command, background=action.background)
  26. async def kill(self, action: CmdKillAction) -> Observation:
  27. cmd = self.sandbox.kill_background(action.id)
  28. return CmdOutputObservation(
  29. content=f'Background command with id {action.id} has been killed.',
  30. command_id=action.id,
  31. command=cmd.command,
  32. exit_code=0,
  33. )
  34. async def run_ipython(self, action: IPythonRunCellAction) -> Observation:
  35. # echo "import math" | execute_cli
  36. # write code to a temporary file and pass it to `execute_cli` via stdin
  37. tmp_filepath = os.path.join(
  38. config.workspace_base, '.tmp', '.ipython_execution_tmp.py'
  39. )
  40. pathlib.Path(os.path.dirname(tmp_filepath)).mkdir(parents=True, exist_ok=True)
  41. with open(tmp_filepath, 'w') as tmp_file:
  42. tmp_file.write(action.code)
  43. tmp_filepath_inside_sandbox = os.path.join(
  44. config.workspace_mount_path_in_sandbox,
  45. '.tmp',
  46. '.ipython_execution_tmp.py',
  47. )
  48. obs = self._run_command(
  49. f'execute_cli < {tmp_filepath_inside_sandbox}', background=False
  50. )
  51. return IPythonRunCellObservation(content=obs.content, code=action.code)
  52. async def read(self, action: FileReadAction) -> Observation:
  53. working_dir = self.sandbox.get_working_directory()
  54. return await read_file(action.path, working_dir, action.start, action.end)
  55. async def write(self, action: FileWriteAction) -> Observation:
  56. working_dir = self.sandbox.get_working_directory()
  57. return await write_file(
  58. action.path, working_dir, action.content, action.start, action.end
  59. )
  60. async def browse(self, action: BrowseURLAction) -> Observation:
  61. return await browse(action, self.browser)
  62. async def recall(self, action: AgentRecallAction) -> Observation:
  63. return NullObservation('')
  64. def _run_command(self, command: str, background=False) -> Observation:
  65. if background:
  66. return self._run_background(command)
  67. else:
  68. return self._run_immediately(command)
  69. def _run_immediately(self, command: str) -> Observation:
  70. try:
  71. exit_code, output = self.sandbox.execute(command)
  72. return CmdOutputObservation(
  73. command_id=-1, content=output, command=command, exit_code=exit_code
  74. )
  75. except UnicodeDecodeError:
  76. return ErrorObservation('Command output could not be decoded as utf-8')
  77. def _run_background(self, command: str) -> Observation:
  78. bg_cmd = self.sandbox.execute_in_background(command)
  79. content = f'Background command started. To stop it, send a `kill` action with id {bg_cmd.pid}'
  80. return CmdOutputObservation(
  81. content=content,
  82. command_id=bg_cmd.pid,
  83. command=command,
  84. exit_code=0,
  85. )