__init__.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import asyncio
  2. from typing import List, Callable, Tuple
  3. from opendevin.state import State
  4. from opendevin.agent import Agent
  5. from opendevin.action import (
  6. Action,
  7. NullAction,
  8. FileReadAction,
  9. FileWriteAction,
  10. AgentFinishAction,
  11. )
  12. from opendevin.observation import (
  13. Observation,
  14. NullObservation
  15. )
  16. from .command_manager import CommandManager
  17. def print_with_indent(text: str):
  18. print("\t"+text.replace("\n","\n\t"), flush=True)
  19. class AgentController:
  20. def __init__(
  21. self,
  22. agent: Agent,
  23. workdir: str,
  24. max_iterations: int = 100,
  25. callbacks: List[Callable] = [],
  26. ):
  27. self.agent = agent
  28. self.max_iterations = max_iterations
  29. self.workdir = workdir
  30. self.command_manager = CommandManager(workdir)
  31. self.callbacks = callbacks
  32. self.state_updated_info: List[Tuple[Action, Observation]] = []
  33. def get_current_state(self) -> State:
  34. # update observations & actions
  35. state = State(
  36. background_commands_obs=self.command_manager.get_background_obs(),
  37. updated_info=self.state_updated_info,
  38. )
  39. self.state_updated_info = []
  40. return state
  41. def add_observation(self, observation: Observation):
  42. self.state_updated_info.append((NullAction(), observation))
  43. async def start_loop(self, task_instruction: str):
  44. finished = False
  45. self.agent.instruction = task_instruction
  46. for i in range(self.max_iterations):
  47. try:
  48. finished = await self.step(i)
  49. except Exception as e:
  50. print("Error in loop", e, flush=True)
  51. break
  52. if finished:
  53. break
  54. if not finished:
  55. print("Exited before finishing", flush=True)
  56. async def step(self, i: int):
  57. print("\n\n==============", flush=True)
  58. print("STEP", i, flush=True)
  59. log_obs = self.command_manager.get_background_obs()
  60. for obs in log_obs:
  61. self.add_observation(obs)
  62. await self._run_callbacks(obs)
  63. print_with_indent("\nBACKGROUND LOG:\n%s" % obs)
  64. state: State = self.get_current_state()
  65. action: Action = self.agent.step(state)
  66. print_with_indent("\nACTION:\n%s" % action)
  67. await self._run_callbacks(action)
  68. if isinstance(action, AgentFinishAction):
  69. print_with_indent("\nFINISHED")
  70. return True
  71. if isinstance(action, (FileReadAction, FileWriteAction)):
  72. action_cls = action.__class__
  73. _kwargs = action.__dict__
  74. _kwargs["base_path"] = self.workdir
  75. action = action_cls(**_kwargs)
  76. print(action, flush=True)
  77. if action.executable:
  78. observation: Observation = action.run(self)
  79. else:
  80. observation = NullObservation("")
  81. print_with_indent("\nOBSERVATION:\n%s" % observation)
  82. self.state_updated_info.append((action, observation))
  83. await self._run_callbacks(observation)
  84. async def _run_callbacks(self, event):
  85. if event is None:
  86. return
  87. for callback in self.callbacks:
  88. idx = self.callbacks.index(callback)
  89. try:
  90. callback(event)
  91. except Exception as e:
  92. print("Callback error:" + str(idx), e, flush=True)
  93. pass
  94. await asyncio.sleep(0.001) # Give back control for a tick, so we can await in callbacks