manager.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import asyncio
  2. import os
  3. from typing import Optional
  4. from opendevin import config
  5. from opendevin.action import (
  6. Action,
  7. NullAction,
  8. )
  9. from opendevin.agent import Agent
  10. from opendevin.controller import AgentController
  11. from opendevin.llm.llm import LLM
  12. from opendevin.observation import NullObservation, Observation, UserMessageObservation
  13. from opendevin.server.session import session_manager
  14. from opendevin.schema import ActionType
  15. from opendevin.logging import opendevin_logger as logger
  16. DEFAULT_API_KEY = config.get("LLM_API_KEY")
  17. DEFAULT_BASE_URL = config.get("LLM_BASE_URL")
  18. DEFAULT_WORKSPACE_DIR = config.get("WORKSPACE_DIR")
  19. LLM_MODEL = config.get("LLM_MODEL")
  20. CONTAINER_IMAGE = config.get("SANDBOX_CONTAINER_IMAGE")
  21. MAX_ITERATIONS = config.get("MAX_ITERATIONS")
  22. class AgentManager:
  23. """Represents a session with an agent.
  24. Attributes:
  25. controller: The AgentController instance for controlling the agent.
  26. agent: The Agent instance representing the agent.
  27. agent_task: The task representing the agent's execution.
  28. """
  29. sid: str
  30. def __init__(self, sid):
  31. """Initializes a new instance of the Session class."""
  32. self.sid = sid
  33. self.controller: Optional[AgentController] = None
  34. self.agent: Optional[Agent] = None
  35. self.agent_task = None
  36. async def send_error(self, message):
  37. """Sends an error message to the client.
  38. Args:
  39. message: The error message to send.
  40. """
  41. await session_manager.send_error(self.sid, message)
  42. async def send_message(self, message):
  43. """Sends a message to the client.
  44. Args:
  45. message: The message to send.
  46. """
  47. await session_manager.send_message(self.sid, message)
  48. async def send(self, data):
  49. """Sends data to the client.
  50. Args:
  51. data: The data to send.
  52. """
  53. await session_manager.send(self.sid, data)
  54. async def dispatch(self, action: str | None, data: dict):
  55. """Dispatches actions to the agent from the client."""
  56. if action is None:
  57. await self.send_error("Invalid action")
  58. return
  59. if action == ActionType.INIT:
  60. await self.create_controller(data)
  61. elif action == ActionType.START:
  62. await self.start_task(data)
  63. else:
  64. if self.controller is None:
  65. await self.send_error("No agent started. Please wait a second...")
  66. elif action == ActionType.CHAT:
  67. self.controller.add_history(
  68. NullAction(), UserMessageObservation(data["message"])
  69. )
  70. else:
  71. await self.send_error("I didn't recognize this action:" + action)
  72. async def create_controller(self, start_event=None):
  73. """Creates an AgentController instance.
  74. Args:
  75. start_event: The start event data (optional).
  76. """
  77. directory = DEFAULT_WORKSPACE_DIR
  78. if start_event and "directory" in start_event["args"]:
  79. directory = start_event["args"]["directory"]
  80. agent_cls = "MonologueAgent"
  81. if start_event and "agent_cls" in start_event["args"]:
  82. agent_cls = start_event["args"]["agent_cls"]
  83. model = LLM_MODEL
  84. if start_event and "model" in start_event["args"]:
  85. model = start_event["args"]["model"]
  86. api_key = DEFAULT_API_KEY
  87. if start_event and "api_key" in start_event["args"]:
  88. api_key = start_event["args"]["api_key"]
  89. api_base = DEFAULT_BASE_URL
  90. if start_event and "api_base" in start_event["args"]:
  91. api_base = start_event["args"]["api_base"]
  92. container_image = CONTAINER_IMAGE
  93. if start_event and "container_image" in start_event["args"]:
  94. container_image = start_event["args"]["container_image"]
  95. max_iterations = MAX_ITERATIONS
  96. if start_event and "max_iterations" in start_event["args"]:
  97. max_iterations = start_event["args"]["max_iterations"]
  98. # double check preventing error occurs
  99. if directory == "":
  100. directory = DEFAULT_WORKSPACE_DIR
  101. if agent_cls == "":
  102. agent_cls = "MonologueAgent"
  103. if model == "":
  104. model = LLM_MODEL
  105. if not os.path.exists(directory):
  106. logger.info("Workspace directory %s does not exist. Creating it...", directory)
  107. os.makedirs(directory)
  108. directory = os.path.relpath(directory, os.getcwd())
  109. llm = LLM(model=model, api_key=api_key, base_url=api_base)
  110. AgentCls = Agent.get_cls(agent_cls)
  111. self.agent = AgentCls(llm)
  112. try:
  113. self.controller = AgentController(
  114. id=self.sid,
  115. agent=self.agent,
  116. workdir=directory,
  117. max_iterations=max_iterations,
  118. container_image=container_image,
  119. callbacks=[self.on_agent_event],
  120. )
  121. except Exception:
  122. logger.exception("Error creating controller.")
  123. await self.send_error(
  124. "Error creating controller. Please check Docker is running using `docker ps`."
  125. )
  126. return
  127. await self.send({"action": ActionType.INIT, "message": "Control loop started."})
  128. async def start_task(self, start_event):
  129. """Starts a task for the agent.
  130. Args:
  131. start_event: The start event data.
  132. """
  133. if "task" not in start_event["args"]:
  134. await self.send_error("No task specified")
  135. return
  136. await self.send_message("Starting new task...")
  137. task = start_event["args"]["task"]
  138. if self.controller is None:
  139. await self.send_error("No agent started. Please wait a second...")
  140. return
  141. try:
  142. self.agent_task = await asyncio.create_task(
  143. self.controller.start_loop(task), name="agent loop"
  144. )
  145. except Exception:
  146. await self.send_error("Error during task loop.")
  147. def on_agent_event(self, event: Observation | Action):
  148. """Callback function for agent events.
  149. Args:
  150. event: The agent event (Observation or Action).
  151. """
  152. if isinstance(event, NullAction):
  153. return
  154. if isinstance(event, NullObservation):
  155. return
  156. event_dict = event.to_dict()
  157. asyncio.create_task(self.send(event_dict), name="send event in callback")
  158. def disconnect(self):
  159. self.websocket = None
  160. if self.agent_task:
  161. self.agent_task.cancel()
  162. if self.controller is not None:
  163. self.controller.command_manager.shell.close()