-
Notifications
You must be signed in to change notification settings - Fork 7k
Separate agent controller and server via EventStream #1538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
In console it works well. With UI, I think this one might be relevant: I ran with CodeAct, gave a task, it wrote a file. OK. Then I said, "run it".
That said, this refactoring is a beauty. ❤️ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I played with it anywhere near enough yet, but I see we have 0.5.0 as relatively stable version, I think we can move forward if you see fit, the next ones will also be opportunities to find things.
@rbren thank you! I pulled the newest version of this branch and all worked perfect with ollama/llama3:8b-instruct-q8_0. log details❯ export WORKSPACE_DIR=/Users/isavita/code/workspace
docker run \
--pull=always \
-e SANDBOX_USER_ID=$(id -u) \
-e LLM_API_KEY \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_DIR \
-v $WORKSPACE_DIR:/opt/workspace_base \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 2000:3000 \
--add-host host.docker.internal=host-gateway \
ghcr.io/opendevin/opendevin:1538-merge
1538-merge: Pulling from opendevin/opendevin
Digest: sha256:e318edd445b5377e44161e0831932662d4fae794333208e1042b08cc22a419b6
Status: Image is up to date for ghcr.io/opendevin/opendevin:1538-merge
Docker socket group id: 0
INFO: Started server process [33]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:3000 (Press CTRL+C to quit)
INFO: 127.0.0.1:59772 - "GET / HTTP/1.1" 307 Temporary Redirect
INFO: 127.0.0.1:59772 - "GET /index.html HTTP/1.1" 200 OK
INFO: 127.0.0.1:59772 - "GET /assets/index-DZ5GKr_e.js HTTP/1.1" 200 OK
INFO: 127.0.0.1:59778 - "GET /assets/index-DD3lkNKs.css HTTP/1.1" 200 OK
10:12:13 - opendevin:ERROR: auth.py:33 - Invalid token
10:12:13 - opendevin:INFO: listen.py:77 - Invalid or missing credentials, generating new session ID: 78ed30d6-0ad4-421c-b4df-7359297ea5b5
INFO: 127.0.0.1:59772 - "GET /api/auth HTTP/1.1" 200 OK
INFO: 127.0.0.1:59778 - "GET /locales/en/translation.json HTTP/1.1" 200 OK
INFO: 127.0.0.1:59772 - "GET /locales/en-US/translation.json HTTP/1.1" 404 Not Found
INFO: ('127.0.0.1', 59779) - "WebSocket /ws?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaWQiOiI3OGVkMzBkNi0wYWQ0LTQyMWMtYjRkZi03MzU5Mjk3ZWE1YjUifQ.JaDAkpOx--X295rTQUYRrHL-3_NldhbqvxdqeSUaKQY" [accepted]
Starting loop_recv for sid: 78ed30d6-0ad4-421c-b4df-7359297ea5b5
INFO: connection open
INFO: 127.0.0.1:59778 - "GET /api/refresh-files HTTP/1.1" 200 OK
INFO: 127.0.0.1:59778 - "GET /api/litellm-models HTTP/1.1" 200 OK
INFO: 127.0.0.1:59772 - "GET /api/messages/total HTTP/1.1" 200 OK
INFO: 127.0.0.1:59778 - "GET /api/messages/total HTTP/1.1" 200 OK
INFO: 127.0.0.1:59780 - "GET /api/agents HTTP/1.1" 200 OK
INFO: 127.0.0.1:59772 - "GET /favicon-32x32.png HTTP/1.1" 200 OK
10:12:14 - opendevin:INFO: agent.py:156 - Creating agent CodeActAgent using LLM gpt-3.5-turbo
10:12:14 - opendevin:INFO: llm.py:71 - Initializing LLM with model: gpt-3.5-turbo
10:12:14 - opendevin:INFO: ssh_box.py:67 - SSHBox is running as opendevin user with USER_ID=501 in the sandbox
10:12:15 - opendevin:INFO: ssh_box.py:370 - Container stopped
10:12:15 - opendevin:WARNING: ssh_box.py:382 - Using port forwarding for Mac OS. Server started by OpenDevin will not be accessible from the host machine at the moment. See https://github.com/OpenDevin/OpenDevin/issues/897 for more information.
10:12:15 - opendevin:INFO: ssh_box.py:391 - Mounting workspace directory: /Users/isavita/code/workspace
10:12:15 - opendevin:INFO: ssh_box.py:412 - Container started
10:12:16 - opendevin:INFO: ssh_box.py:428 - waiting for container to start: 1, container status: running
10:12:16 - opendevin:INFO: ssh_box.py:191 - Connecting to opendevin@localhost via ssh. If you encounter any issues, you can try `ssh -v -p 59787 opendevin@localhost` with the password '29a039bd-8c39-432a-baad-686ab38bf1e2' and report the issue on GitHub. If you started OpenDevin with `docker run`, you should try `ssh -v -p 59787 opendevin@localhost` with the password '29a039bd-8c39-432a-baad-686ab38bf1e2 on the host machine (where you started the container).
10:12:17 - opendevin:INFO: mixin.py:24 - Copied files from [/Users/isavita/git/OpenDevin/opendevin/runtime/plugins/jupyter] to [/opendevin/plugins/jupyter] inside sandbox.
10:12:17 - opendevin:INFO: mixin.py:32 - Initializing plugin [jupyter] by executing [/opendevin/plugins/jupyter/setup.sh] in the sandbox.
...
JupyterKernelGateway started with PID: 92
Execution server started with PID: 93
Jupyter kernel ready.
10:12:20 - opendevin:INFO: mixin.py:24 - Copied files from [/Users/isavita/git/OpenDevin/opendevin/runtime/plugins/swe_agent_commands] to [/opendevin/plugins/swe_agent_commands] inside sandbox.
10:12:20 - opendevin:INFO: mixin.py:32 - Initializing plugin [swe_agent_commands] by executing [/opendevin/plugins/swe_agent_commands/setup_default.sh] in the sandbox.
10:12:21 - opendevin:INFO: mixin.py:40 - Plugin swe_agent_commands initialized successfully
...
10:12:21 - opendevin:INFO: mixin.py:50 - Sourced ~/.bashrc successfully
10:12:21 - opendevin:INFO: browser_env.py:38 - Starting browser env...
10:12:25 - opendevin:INFO: browser_env.py:51 - Browser env started.
10:13:07 - opendevin:INFO: agent.py:156 - Creating agent CodeActAgent using LLM ollama/llama3:8b-instruct-q8_0
10:13:07 - opendevin:INFO: llm.py:71 - Initializing LLM with model: ollama/llama3:8b-instruct-q8_0
10:13:07 - opendevin:INFO: ssh_box.py:67 - SSHBox is running as opendevin user with USER_ID=501 in the sandbox
10:13:07 - opendevin:INFO: ssh_box.py:370 - Container stopped
10:13:07 - opendevin:WARNING: ssh_box.py:382 - Using port forwarding for Mac OS. Server started by OpenDevin will not be accessible from the host machine at the moment. See https://github.com/OpenDevin/OpenDevin/issues/897 for more information.
10:13:07 - opendevin:INFO: ssh_box.py:391 - Mounting workspace directory: /Users/isavita/code/workspace
10:13:08 - opendevin:INFO: ssh_box.py:412 - Container started
...
JupyterKernelGateway started with PID: 91
Execution server started with PID: 92
Jupyter kernel ready.
10:13:13 - opendevin:INFO: mixin.py:24 - Copied files from [/Users/isavita/git/OpenDevin/opendevin/runtime/plugins/swe_agent_commands] to [/opendevin/plugins/swe_agent_commands] inside sandbox.
10:13:13 - opendevin:INFO: mixin.py:32 - Initializing plugin [swe_agent_commands] by executing [/opendevin/plugins/swe_agent_commands/setup_default.sh] in the sandbox.
10:13:14 - opendevin:INFO: mixin.py:40 - Plugin swe_agent_commands initialized successfully
:Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: flake8 in /usr/local/lib/python3.10/dist-packages (7.0.0)
Requirement already satisfied: mccabe<0.8.0,>=0.7.0 in /usr/local/lib/python3.10/dist-packages (from flake8) (0.7.0)
Requirement already satisfied: pycodestyle<2.12.0,>=2.11.0 in /usr/local/lib/python3.10/dist-packages (from flake8) (2.11.1)
Requirement already satisfied: pyflakes<3.3.0,>=3.2.0 in /usr/local/lib/python3.10/dist-packages (from flake8) (3.2.0)
10:13:14 - opendevin:INFO: mixin.py:50 - Sourced ~/.bashrc successfully
10:13:14 - opendevin:INFO: browser_env.py:38 - Starting browser env...
10:13:17 - opendevin:INFO: browser_env.py:51 - Browser env started.
==============
STEP 0
10:13:54 - PLAN
## Context
Advent of Code is an annual series of programming challenges that take place in December. Each day, a new problem is released, and participants must write code to solve it.
## Task
--- Day 1: The Tyranny of the Rocket Equation ---
Santa has become stranded at the edge of the Solar System while delivering presents to other planets! To accurately calculate his position in space, safely align his warp drive, and return to Earth in time to save Christmas, he needs you to bring him measurements from fifty stars.
Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck!
The Elves quickly load you into a spacecraft and prepare to launch.
At the first Go / No Go poll, every Elf is Go until the Fuel Counter-Upper. They haven't determined the amount of fuel required yet.
Fuel required to launch a given module is based on its mass. Specifically, to find the fuel required for a module, take its mass, divide by three, round down, and subtract 2.
For example:
For a mass of 12, divide by 3 and round down to get 4, then subtract 2 to get 2.
For a mass of 14, dividing by 3 and rounding down still yields 4, so the fuel required is also 2.
For a mass of 1969, the fuel required is 654.
For a mass of 100756, the fuel required is 33583.
The Fuel Counter-Upper needs to know the total fuel requirement. To find it, individually calculate the fuel needed for the mass of each module (your puzzle input), then add together all the fuel values.
What is the sum of the fuel requirements for all of the modules on your spacecraft?
## Constraints
- You should implement the solution in Python.
- I will provide you with the input data as a file with the name 'input.txt'.
- The program should print the solution of the task to standard output (stdout) and you should provide me with the code file and the solution output.
## Instructions
1. You should break down the task into smaller sub-tasks and solve each sub-task using TDD(Test-Driven Development) approach.
2. You should write unit tests based on the task examples.
3. You should save and run the tests and the task solution to make sure they work as expected.
## Completion Criteria
- The program should print the correct answer to the task.
- You have run the task solution program and provide the answer to me.
10:15:00 - ACTION
I'm excited to help you with this Advent of Code challenge!
To get started, I'll break down the task into smaller sub-tasks and solve each one using TDD (Test-Driven Development) approach.
First, let's define the function that calculates the fuel required for a given mass. We can start by writing a test for this function:
<code>
import unittest
def calculate_fuel(mass):
# TO DO: implement the calculation logic here
pass
class TestCalculateFuel(unittest.TestCase):
def test_calculate_fuel(self):
self.assertEqual(calculate_fuel(12), 2)
self.assertEqual(calculate_fuel(14), 2)
self.assertEqual(calculate_fuel(1969), 654)
self.assertEqual(calculate_fuel(100756), 33583)
if __name__ == '__main__':
unittest.main()
</code>
Now, let's implement the `calculate_fuel` function:
<code>
def calculate_fuel(mass):
fuel = mass // 3 - 2
return max(fuel, 0)
</code>
This implementation uses integer division (`//`) to divide the mass by 3 and then subtracts 2. We also use the `max` function to ensure that the result is not negative.
Next, let's write a test for the main task:
<code>
class TestMain(unittest.TestCase):
def test_main(self):
with open('input.txt', 'r') as f:
masses = [int(line.strip()) for line in f]
total_fuel = sum(calculate_fuel(mass) for mass in masses)
self.assertEqual(total_fuel, ???)
</code>
Here, we read the input data from `input.txt` and calculate the total fuel required by summing up the results of `calculate_fuel` for each mass.
Finally, let's run the tests to ensure that everything works as expected:
<code>
if __name__ == '__main__':
unittest.main()
</code>
Once we've written and tested all the code, we can run it with the input data to get the solution:
<code>
with open('input.txt', 'r') as f:
masses = [int(line.strip()) for line in f]
total_fuel = sum(calculate_fuel(mass) for mass in masses)
print(total_fuel)
</code>
This will output the correct answer to the task.
Please provide me with the input data file `input.txt` and I'll run the code to get the solution. |
Thanks all! @enyst it looks like your issue was a bad LLM response (it set |
…n into rb/event-stream
Turns out the bad action was being sent by the UI--maybe a merge issue? It sent me down a huge rabbit hole of fixes for the interactive "waiting for user message" stuff. But everything seems to be working well now! |
elif event.agent_state == AgentState.FINISHED: | ||
await self.set_agent_state_to(AgentState.FINISHED) | ||
else: | ||
logger.warning(f'Unknown agent state: {event.agent_state}') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems there're several other states in AgentState, like: ERROR/INIT/AWAITING_USER_INPUT, maybe logger.warning(f'Unexpected agent state: {event.agent_state}')
is better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call!
elif event.agent_state == AgentState.STOPPED: | ||
await self.set_agent_state_to(AgentState.STOPPED) | ||
elif event.agent_state == AgentState.FINISHED: | ||
await self.set_agent_state_to(AgentState.FINISHED) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this if/elif more simplified? now, agent_state == StateX, set_agent_state_to = StateX. maybe an array contains all allowed states, and if event.agent_state is in the array, just set it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had this because the typing was complaining (event.agent_state
is str instead of AgentState). But I just added a type: ignore 😄
Architecture refactor progress:
rearrange directory structureThe main goal here is to start creating separation between the server and the agent controller. Ideally they should be able to communicate over a network connection--though we're not quite there.
Now, when there's a request to change agent state (init, start, pause, stop) a
ChangeAgentStateAction
gets put into the event stream. Once the agent controller has responded, it puts aAgentStateChangedObservation
into the event stream.Two exceptions to this flow:
init
events, the server actually instantiates the controller firststart
events, the server passes the task to the controller first (I think this case we can make smoother in the future)Some other stuff in here:
pause
is nowpaused
,start/resume
are nowrunning