runtime.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. from opendevin.core.config import config
  2. from opendevin.events.action import (
  3. AgentRecallAction,
  4. BrowseInteractiveAction,
  5. BrowseURLAction,
  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.events.stream import EventStream
  19. from opendevin.runtime import Sandbox
  20. from opendevin.runtime.runtime import Runtime
  21. from opendevin.storage.local import LocalFileStore
  22. from .browse import browse
  23. from .files import read_file, write_file
  24. class ServerRuntime(Runtime):
  25. def __init__(
  26. self,
  27. event_stream: EventStream,
  28. sid: str = 'default',
  29. sandbox: Sandbox | None = None,
  30. ):
  31. super().__init__(event_stream, sid, sandbox)
  32. self.file_store = LocalFileStore(config.workspace_base)
  33. async def run(self, action: CmdRunAction) -> Observation:
  34. return self._run_command(action.command)
  35. async def run_ipython(self, action: IPythonRunCellAction) -> Observation:
  36. obs = self._run_command(
  37. ("cat > /tmp/opendevin_jupyter_temp.py <<'EOL'\n" f'{action.code}\n' 'EOL'),
  38. )
  39. # run the code
  40. obs = self._run_command('cat /tmp/opendevin_jupyter_temp.py | execute_cli')
  41. output = obs.content
  42. if 'pip install' in action.code:
  43. print(output)
  44. package_names = action.code.split(' ', 2)[-1]
  45. is_single_package = ' ' not in package_names
  46. if 'Successfully installed' in output:
  47. restart_kernel = 'import IPython\nIPython.Application.instance().kernel.do_shutdown(True)'
  48. if (
  49. 'Note: you may need to restart the kernel to use updated packages.'
  50. in output
  51. ):
  52. self._run_command(
  53. (
  54. "cat > /tmp/opendevin_jupyter_temp.py <<'EOL'\n"
  55. f'{restart_kernel}\n'
  56. 'EOL'
  57. )
  58. )
  59. obs = self._run_command(
  60. 'cat /tmp/opendevin_jupyter_temp.py | execute_cli'
  61. )
  62. output = '[Package installed successfully]'
  63. if "{'status': 'ok', 'restart': True}" != obs.content.strip():
  64. print(obs.content)
  65. output += (
  66. '\n[But failed to restart the kernel to load the package]'
  67. )
  68. else:
  69. output += (
  70. '\n[Kernel restarted successfully to load the package]'
  71. )
  72. # re-init the kernel after restart
  73. if action.kernel_init_code:
  74. obs = self._run_command(
  75. (
  76. f"cat > /tmp/opendevin_jupyter_init.py <<'EOL'\n"
  77. f'{action.kernel_init_code}\n'
  78. 'EOL'
  79. ),
  80. )
  81. obs = self._run_command(
  82. 'cat /tmp/opendevin_jupyter_init.py | execute_cli',
  83. )
  84. elif (
  85. is_single_package
  86. and f'Requirement already satisfied: {package_names}' in output
  87. ):
  88. output = '[Package already installed]'
  89. return IPythonRunCellObservation(content=output, code=action.code)
  90. async def read(self, action: FileReadAction) -> Observation:
  91. # TODO: use self.file_store
  92. working_dir = self.sandbox.get_working_directory()
  93. return await read_file(action.path, working_dir, action.start, action.end)
  94. async def write(self, action: FileWriteAction) -> Observation:
  95. # TODO: use self.file_store
  96. working_dir = self.sandbox.get_working_directory()
  97. return await write_file(
  98. action.path, working_dir, action.content, action.start, action.end
  99. )
  100. async def browse(self, action: BrowseURLAction) -> Observation:
  101. return await browse(action, self.browser)
  102. async def browse_interactive(self, action: BrowseInteractiveAction) -> Observation:
  103. return await browse(action, self.browser)
  104. async def recall(self, action: AgentRecallAction) -> Observation:
  105. return NullObservation('')
  106. def _run_command(self, command: str) -> Observation:
  107. try:
  108. exit_code, output = self.sandbox.execute(command)
  109. if 'pip install' in command:
  110. package_names = command.split(' ', 2)[-1]
  111. is_single_package = ' ' not in package_names
  112. print(output)
  113. if 'Successfully installed' in output:
  114. output = '[Package installed successfully]'
  115. elif (
  116. is_single_package
  117. and f'Requirement already satisfied: {package_names}' in output
  118. ):
  119. output = '[Package already installed]'
  120. return CmdOutputObservation(
  121. command_id=-1, content=str(output), command=command, exit_code=exit_code
  122. )
  123. except UnicodeDecodeError:
  124. return ErrorObservation('Command output could not be decoded as utf-8')