enterprise/enterprise_local/README.md
You have a few options here, which are expanded on below:
Before starting, make sure you have the following tools installed:
brew install sopssudo apt-get install sops or download from GitHub releaseschoco install sops or download from GitHub releasesThis option will allow you to modify both the OpenHands code and the code in this repo, and see the changes in real-time.
This option works best for most scenarios. The only thing it's missing is the GitHub events webhook, which is not necessary for most development.
The open source OpenHands repo should be cloned as a sibling directory,
in ../OpenHands. This is hard-coded in the pyproject.toml (edit if necessary)
If you're doing this the first time, you may need to run
poetry update openhands-ai
First run this to retrieve Github App secrets
gcloud auth application-default login
gcloud config set project global-432717
enterprise_local/decrypt_env.sh /path/to/root/of/deploy/repo
Now run this to generate a .env file, which will used to run SAAS locally
python -m pip install PyYAML
export LITE_LLM_API_KEY=<your LLM API key>
python enterprise_local/convert_to_env.py
By default the application will log in json, you can override.
export LOG_PLAIN_TEXT=1
Start the frontend like you normally would in the open source OpenHands repo.
make build
make start-backend
You should have a server running on localhost:3000, similar to the open source backend.
Oauth should work properly.
Follow all the steps above, then setup redis:
docker run -p 6379:6379 --name openhands-redis -d redis
export REDIS_HOST=host.docker.internal # you may want this to be localhost
export REDIS_PORT=6379
(see above)
Develop on Openhands locally. When ready, run the following inside Openhands repo (not the Deploy repo)
docker build -f containers/app/Dockerfile -t openhands .
Build the SAAS image locally inside Deploy repo. Note that openhands is the name of the image built in Step 2
docker build -t openhands-saas ./app/ --build-arg BASE="openhands"
Run in a separate terminal
ngrok http 3000
There will be a line
Forwarding https://bc71-2603-7000-5000-1575-e4a6-697b-589e-5801.ngrok-free.app
Remember this URL as it will be used in Step 5 and 6
Using the URL found in Step 4, add another callback URL (https://bc71-2603-7000-5000-1575-e4a6-697b-589e-5801.ngrok-free.app/oauth/github/callback)
This is the last step! Run SAAS openhands locally using
docker run --env-file ./app/.env -p 3000:3000 openhands-saas
Note --env-file is what injects the .env file created in Step 1
Visit the tunnel domain found in Step 4 to run the app (https://bc71-2603-7000-5000-1575-e4a6-697b-589e-5801.ngrok-free.app)
Local Development necessitates running a version of OpenHands that is as similar as possible to the version running in the SAAS Environment. Before running these steps, it is assumed you have a local development version of OpenHands running.
A Local redis instance is required for clustered communication between server nodes. The standard docker instance will suffice.
docker run -it -p 6379:6379 --name my-redis -d redis
A Local postgres instance is required. I used the official docker image:
docker run -p 5432:5432 --name my-postgres -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=openhands -d postgres
Run the alembic migrations:
poetry run alembic upgrade head
The VSCode launch.json below sets up 2 servers to test clustering, running independently on localhost:3030 and localhost:3031. Running only the server on 3030 is usually sufficient unless tests of the clustered functionality are required. Secrets may be harvested directly from staging by connecting...
kubectl exec --stdin --tty <POD_NAME> -n <NAMESPACE> -- /bin/bash
And then invoking printenv. NOTE: DO NOT DO THIS WITH PROD!!! (Hopefully by the time you read this, nobody will have access.)
{
"configurations": [
{
"name": "Python Debugger: Python File",
"type": "debugpy",
"request": "launch",
"program": "${file}"
},
{
"name": "OpenHands Deploy",
"type": "debugpy",
"request": "launch",
"module": "uvicorn",
"args": [
"saas_server:app",
"--reload",
"--host",
"0.0.0.0",
"--port",
"3030"
],
"env": {
"DEBUG": "1",
"FILE_STORE": "local",
"REDIS_HOST": "localhost:6379",
"OPENHANDS": "<YOUR LOCAL OPENHANDS DIR>",
"FRONTEND_DIRECTORY": "<YOUR LOCAL OPENHANDS DIR>/frontend/build",
"FILE_STORE_PATH": "<YOUR HOME DIRECTORY>>/.openhands-state",
"OPENHANDS_CONFIG_CLS": "server.config.SaaSServerConfig",
"GITHUB_APP_ID": "1062351",
"GITHUB_APP_PRIVATE_KEY": "<GITHUB PRIVATE KEY>",
"GITHUB_APP_CLIENT_ID": "Iv23lis7eUWDQHIq8US0",
"GITHUB_APP_CLIENT_SECRET": "<GITHUB CLIENT SECRET>",
"POSTHOG_CLIENT_KEY": "<POSTHOG CLIENT KEY>",
"LITE_LLM_API_URL": "https://llm-proxy.staging.all-hands.dev",
"LITE_LLM_TEAM_ID": "62ea39c4-8886-44f3-b7ce-07ed4fe42d2c",
"LITE_LLM_API_KEY": "<LITE LLM API KEY>"
},
"justMyCode": false,
"cwd": "${workspaceFolder}/app"
},
{
"name": "OpenHands Deploy 2",
"type": "debugpy",
"request": "launch",
"module": "uvicorn",
"args": [
"saas_server:app",
"--reload",
"--host",
"0.0.0.0",
"--port",
"3031"
],
"env": {
"DEBUG": "1",
"FILE_STORE": "local",
"REDIS_HOST": "localhost:6379",
"OPENHANDS": "<YOUR LOCAL OPENHANDS DIR>",
"FRONTEND_DIRECTORY": "<YOUR LOCAL OPENHANDS DIR>/frontend/build",
"FILE_STORE_PATH": "<YOUR HOME DIRECTORY>>/.openhands-state",
"OPENHANDS_CONFIG_CLS": "server.config.SaaSServerConfig",
"GITHUB_APP_ID": "1062351",
"GITHUB_APP_PRIVATE_KEY": "<GITHUB PRIVATE KEY>",
"GITHUB_APP_CLIENT_ID": "Iv23lis7eUWDQHIq8US0",
"GITHUB_APP_CLIENT_SECRET": "<GITHUB CLIENT SECRET>",
"POSTHOG_CLIENT_KEY": "<POSTHOG CLIENT KEY>",
"LITE_LLM_API_URL": "https://llm-proxy.staging.all-hands.dev",
"LITE_LLM_TEAM_ID": "62ea39c4-8886-44f3-b7ce-07ed4fe42d2c",
"LITE_LLM_API_KEY": "<LITE LLM API KEY>"
},
"justMyCode": false,
"cwd": "${workspaceFolder}/app"
},
{
"name": "Unit Tests",
"type": "debugpy",
"request": "launch",
"module": "pytest",
"args": [
"./tests/unit",
//"./tests/unit/test_clustered_conversation_manager.py",
"--durations=0"
],
"env": {
"DEBUG": "1"
},
"justMyCode": false,
"cwd": "${workspaceFolder}/app"
},
// set working directory...
]
}