action_manager.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. from typing import List
  2. import traceback
  3. from opendevin import config
  4. from opendevin.observation import CmdOutputObservation
  5. from opendevin.sandbox import DockerExecBox, DockerSSHBox, Sandbox, LocalBox
  6. from opendevin.schema import ConfigType
  7. from opendevin.logger import opendevin_logger as logger
  8. from opendevin.action import (
  9. Action,
  10. )
  11. from opendevin.observation import (
  12. Observation,
  13. AgentErrorObservation,
  14. NullObservation,
  15. )
  16. class ActionManager:
  17. id: str
  18. shell: Sandbox
  19. def __init__(
  20. self,
  21. sid: str,
  22. container_image: str | None = None,
  23. ):
  24. sandbox_type = config.get(ConfigType.SANDBOX_TYPE).lower()
  25. if sandbox_type == 'exec':
  26. self.shell = DockerExecBox(
  27. sid=(sid or 'default'), container_image=container_image
  28. )
  29. elif sandbox_type == 'local':
  30. self.shell = LocalBox()
  31. elif sandbox_type == 'ssh':
  32. self.shell = DockerSSHBox(
  33. sid=(sid or 'default'), container_image=container_image
  34. )
  35. else:
  36. raise ValueError(f'Invalid sandbox type: {sandbox_type}')
  37. async def run_action(self, action: Action, agent_controller) -> Observation:
  38. observation: Observation = NullObservation('')
  39. if not action.executable:
  40. return observation
  41. try:
  42. observation = await action.run(agent_controller)
  43. except Exception as e:
  44. observation = AgentErrorObservation(str(e))
  45. logger.error(e)
  46. traceback.print_exc()
  47. return observation
  48. def run_command(self, command: str, background=False) -> CmdOutputObservation:
  49. if background:
  50. return self._run_background(command)
  51. else:
  52. return self._run_immediately(command)
  53. def _run_immediately(self, command: str) -> CmdOutputObservation:
  54. exit_code, output = self.shell.execute(command)
  55. return CmdOutputObservation(
  56. command_id=-1, content=output, command=command, exit_code=exit_code
  57. )
  58. def _run_background(self, command: str) -> CmdOutputObservation:
  59. bg_cmd = self.shell.execute_in_background(command)
  60. content = f'Background command started. To stop it, send a `kill` action with id {bg_cmd.id}'
  61. return CmdOutputObservation(
  62. content=content,
  63. command_id=bg_cmd.id,
  64. command=command,
  65. exit_code=0,
  66. )
  67. def kill_command(self, id: int) -> CmdOutputObservation:
  68. cmd = self.shell.kill_background(id)
  69. return CmdOutputObservation(
  70. content=f'Background command with id {id} has been killed.',
  71. command_id=id,
  72. command=cmd.command,
  73. exit_code=0,
  74. )
  75. def get_background_obs(self) -> List[CmdOutputObservation]:
  76. obs = []
  77. for _id, cmd in self.shell.background_commands.items():
  78. output = cmd.read_logs()
  79. if output is not None and output != '':
  80. obs.append(
  81. CmdOutputObservation(
  82. content=output, command_id=_id, command=cmd.command
  83. )
  84. )
  85. return obs