runtime.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. from opendevin.events.action import (
  2. AgentRecallAction,
  3. BrowseInteractiveAction,
  4. BrowseURLAction,
  5. CmdKillAction,
  6. CmdRunAction,
  7. FileReadAction,
  8. FileWriteAction,
  9. IPythonRunCellAction,
  10. )
  11. from opendevin.events.observation import (
  12. CmdOutputObservation,
  13. ErrorObservation,
  14. IPythonRunCellObservation,
  15. NullObservation,
  16. Observation,
  17. )
  18. from opendevin.runtime.runtime import Runtime
  19. from .browse import browse
  20. from .files import read_file, write_file
  21. class ServerRuntime(Runtime):
  22. async def run(self, action: CmdRunAction) -> Observation:
  23. return self._run_command(action.command, background=action.background)
  24. async def kill(self, action: CmdKillAction) -> Observation:
  25. cmd = self.sandbox.kill_background(action.command_id)
  26. return CmdOutputObservation(
  27. content=f'Background command with id {action.command_id} has been killed.',
  28. command_id=action.command_id,
  29. command=cmd.command,
  30. exit_code=0,
  31. )
  32. async def run_ipython(self, action: IPythonRunCellAction) -> Observation:
  33. obs = self._run_command(
  34. ('cat > /tmp/opendevin_jupyter_temp.py <<EOL\n' f'{action.code}\n' 'EOL'),
  35. background=False,
  36. )
  37. # run the code
  38. obs = self._run_command(
  39. ('cat /tmp/opendevin_jupyter_temp.py | execute_cli'), background=False
  40. )
  41. output = obs.content
  42. if 'pip install' in action.code and 'Successfully installed' in output:
  43. print(output)
  44. restart_kernel = 'import IPython\nIPython.Application.instance().kernel.do_shutdown(True)'
  45. if (
  46. 'Note: you may need to restart the kernel to use updated packages.'
  47. in output
  48. ):
  49. obs = self._run_command(
  50. (
  51. 'cat > /tmp/opendevin_jupyter_temp.py <<EOL\n'
  52. f'{restart_kernel}\n'
  53. 'EOL'
  54. ),
  55. background=False,
  56. )
  57. obs = self._run_command(
  58. ('cat /tmp/opendevin_jupyter_temp.py | execute_cli'),
  59. background=False,
  60. )
  61. output = 'Package installed successfully'
  62. if "{'status': 'ok', 'restart': True}" != obs.content.strip():
  63. print(obs.content)
  64. output += '\n But failed to restart the kernel'
  65. return IPythonRunCellObservation(content=output, code=action.code)
  66. async def read(self, action: FileReadAction) -> Observation:
  67. working_dir = self.sandbox.get_working_directory()
  68. return await read_file(action.path, working_dir, action.start, action.end)
  69. async def write(self, action: FileWriteAction) -> Observation:
  70. working_dir = self.sandbox.get_working_directory()
  71. return await write_file(
  72. action.path, working_dir, action.content, action.start, action.end
  73. )
  74. async def browse(self, action: BrowseURLAction) -> Observation:
  75. return await browse(action, self.browser)
  76. async def browse_interactive(self, action: BrowseInteractiveAction) -> Observation:
  77. return await browse(action, self.browser)
  78. async def recall(self, action: AgentRecallAction) -> Observation:
  79. return NullObservation('')
  80. def _run_command(self, command: str, background=False) -> Observation:
  81. if background:
  82. return self._run_background(command)
  83. else:
  84. return self._run_immediately(command)
  85. def _run_immediately(self, command: str) -> Observation:
  86. try:
  87. exit_code, output = self.sandbox.execute(command)
  88. if 'pip install' in command and 'Successfully installed' in output:
  89. print(output)
  90. output = 'Package installed successfully'
  91. return CmdOutputObservation(
  92. command_id=-1, content=str(output), command=command, exit_code=exit_code
  93. )
  94. except UnicodeDecodeError:
  95. return ErrorObservation('Command output could not be decoded as utf-8')
  96. def _run_background(self, command: str) -> Observation:
  97. bg_cmd = self.sandbox.execute_in_background(command)
  98. content = f'Background command started. To stop it, send a `kill` action with command_id {bg_cmd.pid}'
  99. return CmdOutputObservation(
  100. content=content,
  101. command_id=bg_cmd.pid,
  102. command=command,
  103. exit_code=0,
  104. )