mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-04-29 03:00:45 -04:00
Compare commits
1 Commits
improve-ch
...
openhands-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faa78e9951 |
1
.devcontainer/README.MD
Normal file
1
.devcontainer/README.MD
Normal file
@@ -0,0 +1 @@
|
||||
The files in this directory configure a development container for GitHub Codespaces.
|
||||
15
.devcontainer/devcontainer.json
Normal file
15
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "OpenHands Codespaces",
|
||||
"image": "mcr.microsoft.com/devcontainers/universal",
|
||||
"customizations":{
|
||||
"vscode":{
|
||||
"extensions": [
|
||||
"ms-python.python"
|
||||
]
|
||||
}
|
||||
},
|
||||
"onCreateCommand": "sh ./.devcontainer/on_create.sh",
|
||||
"postCreateCommand": "make build",
|
||||
"postStartCommand": "USE_HOST_NETWORK=True nohup bash -c 'make run &'"
|
||||
|
||||
}
|
||||
6
.devcontainer/on_create.sh
Normal file
6
.devcontainer/on_create.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
sudo apt update
|
||||
sudo apt install -y netcat
|
||||
sudo add-apt-repository -y ppa:deadsnakes/ppa
|
||||
sudo apt install -y python3.12
|
||||
curl -sSL https://install.python-poetry.org | python3.12 -
|
||||
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@@ -18,7 +18,7 @@ updates:
|
||||
- "chromadb"
|
||||
browsergym:
|
||||
patterns:
|
||||
- "browsergym*"
|
||||
- "browsergym"
|
||||
security-all:
|
||||
applies-to: "security-updates"
|
||||
patterns:
|
||||
|
||||
6
.github/workflows/fe-unit-tests.yml
vendored
6
.github/workflows/fe-unit-tests.yml
vendored
@@ -24,8 +24,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20, 22]
|
||||
fail-fast: true
|
||||
node-version: [20]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -36,9 +35,6 @@ jobs:
|
||||
- name: Install dependencies
|
||||
working-directory: ./frontend
|
||||
run: npm ci
|
||||
- name: Run TypeScript compilation
|
||||
working-directory: ./frontend
|
||||
run: npm run make-i18n && tsc
|
||||
- name: Run tests and collect coverage
|
||||
working-directory: ./frontend
|
||||
run: npm run test:coverage
|
||||
|
||||
7
.github/workflows/ghcr-build.yml
vendored
7
.github/workflows/ghcr-build.yml
vendored
@@ -68,9 +68,6 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: "Set up docker layer caching"
|
||||
uses: satackey/action-docker-layer-caching@v0.0.11
|
||||
continue-on-error: true
|
||||
- name: Build and push app image
|
||||
if: "!github.event.pull_request.head.repo.fork"
|
||||
run: |
|
||||
@@ -294,7 +291,7 @@ jobs:
|
||||
SANDBOX_RUNTIME_CONTAINER_IMAGE=$image_name \
|
||||
TEST_IN_CI=true \
|
||||
RUN_AS_OPENHANDS=false \
|
||||
poetry run pytest -n 3 -raRs --reruns 2 --reruns-delay 5 --cov=openhands --cov-report=xml -s ./tests/runtime --ignore=tests/runtime/test_browsergym_envs.py
|
||||
poetry run pytest -n 3 -raRs --reruns 2 --reruns-delay 5 --cov=openhands --cov-report=xml -s ./tests/runtime
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
@@ -371,7 +368,7 @@ jobs:
|
||||
SANDBOX_RUNTIME_CONTAINER_IMAGE=$image_name \
|
||||
TEST_IN_CI=true \
|
||||
RUN_AS_OPENHANDS=true \
|
||||
poetry run pytest -n 3 -raRs --reruns 2 --reruns-delay 5 --cov=openhands --cov-report=xml -s ./tests/runtime --ignore=tests/runtime/test_browsergym_envs.py
|
||||
poetry run pytest -n 3 -raRs --reruns 2 --reruns-delay 5 --cov=openhands --cov-report=xml -s ./tests/runtime
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
|
||||
3
.github/workflows/lint.yml
vendored
3
.github/workflows/lint.yml
vendored
@@ -30,11 +30,10 @@ jobs:
|
||||
run: |
|
||||
cd frontend
|
||||
npm install --frozen-lockfile
|
||||
- name: Lint and TypeScript compilation
|
||||
- name: Lint
|
||||
run: |
|
||||
cd frontend
|
||||
npm run lint
|
||||
npm run make-i18n && tsc
|
||||
|
||||
# Run lint on the python code
|
||||
lint-python:
|
||||
|
||||
57
.github/workflows/openhands-resolver.yml
vendored
57
.github/workflows/openhands-resolver.yml
vendored
@@ -16,26 +16,17 @@ on:
|
||||
type: string
|
||||
default: "main"
|
||||
description: "Target branch to pull and create PR against"
|
||||
LLM_MODEL:
|
||||
required: false
|
||||
type: string
|
||||
default: "anthropic/claude-3-5-sonnet-20241022"
|
||||
base_container_image:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
description: "Custom sandbox env"
|
||||
secrets:
|
||||
LLM_MODEL:
|
||||
required: false
|
||||
required: true
|
||||
LLM_API_KEY:
|
||||
required: true
|
||||
LLM_BASE_URL:
|
||||
required: false
|
||||
PAT_TOKEN:
|
||||
required: false
|
||||
required: true
|
||||
PAT_USERNAME:
|
||||
required: false
|
||||
required: true
|
||||
|
||||
issues:
|
||||
types: [labeled]
|
||||
@@ -110,14 +101,13 @@ jobs:
|
||||
|
||||
- name: Check required environment variables
|
||||
env:
|
||||
LLM_MODEL: ${{ secrets.LLM_MODEL || inputs.LLM_MODEL }}
|
||||
LLM_MODEL: ${{ secrets.LLM_MODEL }}
|
||||
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
|
||||
PAT_TOKEN: ${{ secrets.PAT_TOKEN }}
|
||||
PAT_USERNAME: ${{ secrets.PAT_USERNAME }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
required_vars=("LLM_MODEL" "LLM_API_KEY")
|
||||
required_vars=("LLM_MODEL" "LLM_API_KEY" "PAT_TOKEN" "PAT_USERNAME")
|
||||
for var in "${required_vars[@]}"; do
|
||||
if [ -z "${!var}" ]; then
|
||||
echo "Error: Required environment variable $var is not set."
|
||||
@@ -125,19 +115,6 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
# Check optional variables and warn about fallbacks
|
||||
if [ -z "$PAT_TOKEN" ]; then
|
||||
echo "Warning: PAT_TOKEN is not set, falling back to GITHUB_TOKEN"
|
||||
fi
|
||||
|
||||
if [ -z "$LLM_BASE_URL" ]; then
|
||||
echo "Warning: LLM_BASE_URL is not set, will use default API endpoint"
|
||||
fi
|
||||
|
||||
if [ -z "$PAT_USERNAME" ]; then
|
||||
echo "Warning: PAT_USERNAME is not set, will use openhands-agent"
|
||||
fi
|
||||
|
||||
- name: Set environment variables
|
||||
run: |
|
||||
if [ -n "${{ github.event.review.body }}" ]; then
|
||||
@@ -161,8 +138,7 @@ jobs:
|
||||
fi
|
||||
|
||||
echo "MAX_ITERATIONS=${{ inputs.max_iterations || 50 }}" >> $GITHUB_ENV
|
||||
echo "SANDBOX_ENV_GITHUB_TOKEN=${{ secrets.PAT_TOKEN || github.token }}" >> $GITHUB_ENV
|
||||
echo "SANDBOX_ENV_BASE_CONTAINER_IMAGE=${{ inputs.base_container_image }}" >> $GITHUB_ENV
|
||||
echo "SANDBOX_ENV_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
# Set branch variables
|
||||
echo "TARGET_BRANCH=${{ inputs.target_branch }}" >> $GITHUB_ENV
|
||||
@@ -170,7 +146,7 @@ jobs:
|
||||
- name: Comment on issue with start message
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.PAT_TOKEN || github.token }}
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
const issueType = process.env.ISSUE_TYPE;
|
||||
github.rest.issues.createComment({
|
||||
@@ -195,9 +171,9 @@ jobs:
|
||||
|
||||
- name: Attempt to resolve issue
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN || github.token }}
|
||||
GITHUB_USERNAME: ${{ secrets.PAT_USERNAME || 'openhands-agent' }}
|
||||
LLM_MODEL: ${{ secrets.LLM_MODEL || inputs.LLM_MODEL }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_USERNAME: ${{ secrets.PAT_USERNAME }}
|
||||
LLM_MODEL: ${{ secrets.LLM_MODEL }}
|
||||
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
|
||||
PYTHONPATH: ""
|
||||
@@ -207,7 +183,7 @@ jobs:
|
||||
--issue-number ${{ env.ISSUE_NUMBER }} \
|
||||
--issue-type ${{ env.ISSUE_TYPE }} \
|
||||
--max-iterations ${{ env.MAX_ITERATIONS }} \
|
||||
--comment-id ${{ env.COMMENT_ID }}
|
||||
--comment-id ${{ env.COMMENT_ID }} \
|
||||
|
||||
- name: Check resolution result
|
||||
id: check_result
|
||||
@@ -229,9 +205,9 @@ jobs:
|
||||
- name: Create draft PR or push branch
|
||||
if: always() # Create PR or branch even if the previous steps fail
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN || github.token }}
|
||||
GITHUB_USERNAME: ${{ secrets.PAT_USERNAME || 'openhands-agent' }}
|
||||
LLM_MODEL: ${{ secrets.LLM_MODEL || inputs.LLM_MODEL }}
|
||||
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
|
||||
GITHUB_USERNAME: ${{ secrets.PAT_USERNAME }}
|
||||
LLM_MODEL: ${{ secrets.LLM_MODEL }}
|
||||
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
|
||||
PYTHONPATH: ""
|
||||
@@ -239,8 +215,7 @@ jobs:
|
||||
if [ "${{ steps.check_result.outputs.RESOLUTION_SUCCESS }}" == "true" ]; then
|
||||
cd /tmp && python -m openhands.resolver.send_pull_request \
|
||||
--issue-number ${{ env.ISSUE_NUMBER }} \
|
||||
--pr-type draft \
|
||||
--reviewer ${{ github.actor }} | tee pr_result.txt && \
|
||||
--pr-type draft | tee pr_result.txt && \
|
||||
grep "draft created" pr_result.txt | sed 's/.*\///g' > pr_number.txt
|
||||
else
|
||||
cd /tmp && python -m openhands.resolver.send_pull_request \
|
||||
@@ -254,7 +229,7 @@ jobs:
|
||||
uses: actions/github-script@v7
|
||||
if: always() # Comment on issue even if the previous steps fail
|
||||
with:
|
||||
github-token: ${{ secrets.PAT_TOKEN || github.token }}
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const issueNumber = ${{ env.ISSUE_NUMBER }};
|
||||
|
||||
2
.github/workflows/py-unit-tests.yml
vendored
2
.github/workflows/py-unit-tests.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
- name: Build Environment
|
||||
run: make build
|
||||
- name: Run Tests
|
||||
run: poetry run pytest --forked -n auto --cov=openhands --cov-report=xml -svv ./tests/unit --ignore=tests/unit/test_memory.py
|
||||
run: poetry run pytest --forked --cov=openhands --cov-report=xml -svv ./tests/unit --ignore=tests/unit/test_memory.py
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
|
||||
@@ -100,7 +100,7 @@ poetry run pytest ./tests/unit/test_*.py
|
||||
To reduce build time (e.g., if no changes were made to the client-runtime component), you can use an existing Docker container image by
|
||||
setting the SANDBOX_RUNTIME_CONTAINER_IMAGE environment variable to the desired Docker image.
|
||||
|
||||
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.15-nikolaik`
|
||||
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.14-nikolaik`
|
||||
|
||||
## Develop inside Docker container
|
||||
|
||||
|
||||
15
README.md
15
README.md
@@ -12,7 +12,7 @@
|
||||
<a href="https://codecov.io/github/All-Hands-AI/OpenHands?branch=main"><img alt="CodeCov" src="https://img.shields.io/codecov/c/github/All-Hands-AI/OpenHands?style=for-the-badge&color=blue"></a>
|
||||
<a href="https://github.com/All-Hands-AI/OpenHands/blob/main/LICENSE"><img src="https://img.shields.io/github/license/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" alt="MIT License"></a>
|
||||
<br/>
|
||||
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2vbfigwev-G03twSpXaErwzYVD4CFiBg"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community"></a>
|
||||
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2tom0er4l-JeNUGHt_AxpEfIBstbLPiw"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community"></a>
|
||||
<a href="https://discord.gg/ESHStjSjD4"><img src="https://img.shields.io/badge/Discord-Join%20Us-purple?logo=discord&logoColor=white&style=for-the-badge" alt="Join our Discord community"></a>
|
||||
<a href="https://github.com/All-Hands-AI/OpenHands/blob/main/CREDITS.md"><img src="https://img.shields.io/badge/Project-Credits-blue?style=for-the-badge&color=FFE165&logo=github&logoColor=white" alt="Credits"></a>
|
||||
<br/>
|
||||
@@ -29,11 +29,6 @@ call APIs, and yes—even copy code snippets from StackOverflow.
|
||||
|
||||
Learn more at [docs.all-hands.dev](https://docs.all-hands.dev), or jump to the [Quick Start](#-quick-start).
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Using OpenHands for work? We'd love to chat! Fill out
|
||||
> [this short form](https://docs.google.com/forms/d/e/1FAIpQLSet3VbGaz8z32gW9Wm-Grl4jpt5WgMXPgJ4EDPVmCETCBpJtQ/viewform)
|
||||
> to join our Design Partner program, where you'll get early access to commercial features and the opportunity to provide input on our product roadmap.
|
||||
|
||||

|
||||
|
||||
## ⚡ Quick Start
|
||||
@@ -43,16 +38,16 @@ See the [Installation](https://docs.all-hands.dev/modules/usage/installation) gu
|
||||
system requirements and more information.
|
||||
|
||||
```bash
|
||||
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.15-nikolaik
|
||||
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.14-nikolaik
|
||||
|
||||
docker run -it --pull=always \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.15-nikolaik \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.14-nikolaik \
|
||||
-e LOG_ALL_EVENTS=true \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-p 3000:3000 \
|
||||
--add-host host.docker.internal:host-gateway \
|
||||
--name openhands-app \
|
||||
docker.all-hands.dev/all-hands-ai/openhands:0.15
|
||||
docker.all-hands.dev/all-hands-ai/openhands:0.14
|
||||
```
|
||||
|
||||
You'll find OpenHands running at [http://localhost:3000](http://localhost:3000)!
|
||||
@@ -87,7 +82,7 @@ troubleshooting resources, and advanced configuration options.
|
||||
OpenHands is a community-driven project, and we welcome contributions from everyone. We do most of our communication
|
||||
through Slack, so this is the best place to start, but we also are happy to have you contact us on Discord or Github:
|
||||
|
||||
- [Join our Slack workspace](https://join.slack.com/t/openhands-ai/shared_invite/zt-2vbfigwev-G03twSpXaErwzYVD4CFiBg) - Here we talk about research, architecture, and future development.
|
||||
- [Join our Slack workspace](https://join.slack.com/t/openhands-ai/shared_invite/zt-2tom0er4l-JeNUGHt_AxpEfIBstbLPiw) - Here we talk about research, architecture, and future development.
|
||||
- [Join our Discord server](https://discord.gg/ESHStjSjD4) - This is a community-run server for general discussion, questions, and feedback.
|
||||
- [Read or post Github Issues](https://github.com/All-Hands-AI/OpenHands/issues) - Check out the issues we're working on, or add your own ideas.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ services:
|
||||
image: openhands:latest
|
||||
container_name: openhands-app-${DATE:-}
|
||||
environment:
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.15-nikolaik}
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.14-nikolaik}
|
||||
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
|
||||
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
|
||||
ports:
|
||||
|
||||
@@ -95,10 +95,10 @@ workspace_base = "./workspace"
|
||||
# AWS secret access key
|
||||
#aws_secret_access_key = ""
|
||||
|
||||
# API key to use (For Headless / CLI only - In Web this is overridden by Session Init)
|
||||
# API key to use
|
||||
api_key = "your-api-key"
|
||||
|
||||
# API base URL (For Headless / CLI only - In Web this is overridden by Session Init)
|
||||
# API base URL
|
||||
#base_url = ""
|
||||
|
||||
# API version
|
||||
@@ -131,7 +131,7 @@ embedding_model = "local"
|
||||
# Maximum number of output tokens
|
||||
#max_output_tokens = 0
|
||||
|
||||
# Model to use. (For Headless / CLI only - In Web this is overridden by Session Init)
|
||||
# Model to use
|
||||
model = "gpt-4o"
|
||||
|
||||
# Number of retries to attempt when an operation fails with the LLM.
|
||||
@@ -217,9 +217,6 @@ llm_config = 'gpt3'
|
||||
# Use host network
|
||||
#use_host_network = false
|
||||
|
||||
# runtime extra build args
|
||||
#runtime_extra_build_args = ["--network=host", "--add-host=host.docker.internal:host-gateway"]
|
||||
|
||||
# Enable auto linting after editing
|
||||
#enable_auto_lint = false
|
||||
|
||||
@@ -240,10 +237,10 @@ llm_config = 'gpt3'
|
||||
##############################################################################
|
||||
[security]
|
||||
|
||||
# Enable confirmation mode (For Headless / CLI only - In Web this is overridden by Session Init)
|
||||
# Enable confirmation mode
|
||||
#confirmation_mode = false
|
||||
|
||||
# The security analyzer to use (For Headless / CLI only - In Web this is overridden by Session Init)
|
||||
# The security analyzer to use
|
||||
#security_analyzer = ""
|
||||
|
||||
#################################### Eval ####################################
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
# Develop in Docker
|
||||
|
||||
> [!WARNING]
|
||||
> This is not officially supported and may not work.
|
||||
|
||||
Install [Docker](https://docs.docker.com/engine/install/) on your host machine and run:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -11,7 +11,7 @@ services:
|
||||
- BACKEND_HOST=${BACKEND_HOST:-"0.0.0.0"}
|
||||
- SANDBOX_API_HOSTNAME=host.docker.internal
|
||||
#
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.15-nikolaik}
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.14-nikolaik}
|
||||
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
|
||||
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
|
||||
ports:
|
||||
|
||||
@@ -27,7 +27,7 @@ Pour plus de détails, veuillez consulter [ce document](https://github.com/All-H
|
||||
|
||||
Nous avons à la fois un espace de travail Slack pour la collaboration sur la construction d'OpenHands et un serveur Discord pour discuter de tout ce qui est lié, par exemple, à ce projet, LLM, agent, etc.
|
||||
|
||||
- [Espace de travail Slack](https://join.slack.com/t/openhands-ai/shared_invite/zt-2vbfigwev-G03twSpXaErwzYVD4CFiBg)
|
||||
- [Espace de travail Slack](https://join.slack.com/t/opendevin/shared_invite/zt-2oikve2hu-UDxHeo8nsE69y6T7yFX_BA)
|
||||
- [Serveur Discord](https://discord.gg/ESHStjSjD4)
|
||||
|
||||
Si vous souhaitez contribuer, n'hésitez pas à rejoindre notre communauté. Simplifions ensemble l'ingénierie logicielle !
|
||||
|
||||
@@ -9,6 +9,7 @@ Si vous trouvez plus d'informations ou une solution de contournement pour l'un d
|
||||
:::tip
|
||||
OpenHands ne prend en charge Windows que via [WSL](https://learn.microsoft.com/en-us/windows/wsl/install).
|
||||
Veuillez vous assurer d'exécuter toutes les commandes à l'intérieur de votre terminal WSL.
|
||||
Consultez les [Notes pour les utilisateurs de WSL sur Windows](troubleshooting/windows) pour des guides de dépannage.
|
||||
:::
|
||||
|
||||
## Problèmes courants
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
|
||||
# Notes pour les utilisateurs de WSL sur Windows
|
||||
|
||||
OpenHands ne prend en charge Windows que via [WSL](https://learn.microsoft.com/en-us/windows/wsl/install).
|
||||
Veuillez vous assurer d'exécuter toutes les commandes dans votre terminal WSL.
|
||||
|
||||
## Dépannage
|
||||
|
||||
### Recommandation : Ne pas exécuter en tant qu'utilisateur root
|
||||
|
||||
Pour des raisons de sécurité, il est fortement recommandé de ne pas exécuter OpenHands en tant qu'utilisateur root, mais en tant qu'utilisateur avec un UID non nul.
|
||||
|
||||
Références :
|
||||
|
||||
* [Pourquoi il est mauvais de se connecter en tant que root](https://askubuntu.com/questions/16178/why-is-it-bad-to-log-in-as-root)
|
||||
* [Définir l'utilisateur par défaut dans WSL](https://www.tenforums.com/tutorials/128152-set-default-user-windows-subsystem-linux-distro-windows-10-a.html#option2)
|
||||
Astuce concernant la 2ème référence : pour les utilisateurs d'Ubuntu, la commande pourrait en fait être "ubuntupreview" au lieu de "ubuntu".
|
||||
|
||||
---
|
||||
### Erreur : 'docker' n'a pas pu être trouvé dans cette distribution WSL 2.
|
||||
|
||||
Si vous utilisez Docker Desktop, assurez-vous de le démarrer avant d'appeler toute commande docker depuis WSL.
|
||||
Docker doit également avoir l'option d'intégration WSL activée.
|
||||
|
||||
---
|
||||
### Installation de Poetry
|
||||
|
||||
* Si vous rencontrez des problèmes pour exécuter Poetry même après l'avoir installé pendant le processus de build, vous devrez peut-être ajouter son chemin binaire à votre environnement :
|
||||
|
||||
```sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
```
|
||||
|
||||
* Si make build s'arrête sur une erreur comme celle-ci :
|
||||
|
||||
```sh
|
||||
ModuleNotFoundError: no module named <module-name>
|
||||
```
|
||||
|
||||
Cela pourrait être un problème avec le cache de Poetry.
|
||||
Essayez d'exécuter ces 2 commandes l'une après l'autre :
|
||||
|
||||
```sh
|
||||
rm -r ~/.cache/pypoetry
|
||||
make build
|
||||
```
|
||||
|
||||
---
|
||||
### L'objet NoneType n'a pas d'attribut 'request'
|
||||
|
||||
Si vous rencontrez des problèmes liés au réseau, tels que `NoneType object has no attribute 'request'` lors de l'exécution de `make run`, vous devrez peut-être configurer les paramètres réseau de WSL2. Suivez ces étapes :
|
||||
|
||||
* Ouvrez ou créez le fichier `.wslconfig` situé à `C:\Users\%username%\.wslconfig` sur votre machine hôte Windows.
|
||||
* Ajoutez la configuration suivante au fichier `.wslconfig` :
|
||||
|
||||
```sh
|
||||
[wsl2]
|
||||
networkingMode=mirrored
|
||||
localhostForwarding=true
|
||||
```
|
||||
|
||||
* Enregistrez le fichier `.wslconfig`.
|
||||
* Redémarrez complètement WSL2 en quittant toutes les instances WSL2 en cours d'exécution et en exécutant la commande `wsl --shutdown` dans votre invite de commande ou terminal.
|
||||
* Après avoir redémarré WSL, essayez d'exécuter à nouveau `make run`.
|
||||
Le problème de réseau devrait être résolu.
|
||||
@@ -27,7 +27,7 @@ OpenHands 是一个社区驱动的项目,我们欢迎每个人的贡献。无
|
||||
|
||||
我们有 Slack 工作区用于协作构建 OpenHands,也有 Discord 服务器用于讨论任何相关的内容,例如此项目、大语言模型、代理等。
|
||||
|
||||
- [Slack 工作区](https://join.slack.com/t/openhands-ai/shared_invite/zt-2vbfigwev-G03twSpXaErwzYVD4CFiBg)
|
||||
- [Slack 工作区](https://join.slack.com/t/opendevin/shared_invite/zt-2oikve2hu-UDxHeo8nsE69y6T7yFX_BA)
|
||||
- [Discord 服务器](https://discord.gg/ESHStjSjD4)
|
||||
|
||||
如果你想做出贡献,欢迎加入我们的社区。让我们一起简化软件工程!
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
:::tip
|
||||
OpenHands 仅通过 [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) 支持 Windows。
|
||||
请确保在您的 WSL 终端内运行所有命令。
|
||||
查看 [Windows 用户的 WSL 注意事项](troubleshooting/windows) 以获取一些故障排除指南。
|
||||
:::
|
||||
|
||||
## 常见问题
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
以下是翻译后的内容:
|
||||
|
||||
# 针对 Windows 上 WSL 用户的注意事项
|
||||
|
||||
OpenHands 仅通过 [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) 支持 Windows。
|
||||
请确保在您的 WSL 终端内运行所有命令。
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 建议: 不要以 root 用户身份运行
|
||||
|
||||
出于安全原因,强烈建议不要以 root 用户身份运行 OpenHands,而是以具有非零 UID 的用户身份运行。
|
||||
|
||||
参考:
|
||||
|
||||
* [为什么以 root 身份登录不好](https://askubuntu.com/questions/16178/why-is-it-bad-to-log-in-as-root)
|
||||
* [在 WSL 中设置默认用户](https://www.tenforums.com/tutorials/128152-set-default-user-windows-subsystem-linux-distro-windows-10-a.html#option2)
|
||||
关于第二个参考的提示:对于 Ubuntu 用户,命令实际上可能是 "ubuntupreview" 而不是 "ubuntu"。
|
||||
|
||||
---
|
||||
### 错误: 在此 WSL 2 发行版中找不到 'docker'。
|
||||
|
||||
如果您正在使用 Docker Desktop,请确保在从 WSL 内部调用任何 docker 命令之前启动它。
|
||||
Docker 还需要激活 WSL 集成选项。
|
||||
|
||||
---
|
||||
### Poetry 安装
|
||||
|
||||
* 如果您在构建过程中安装 Poetry 后仍然面临运行 Poetry 的问题,您可能需要将其二进制路径添加到环境中:
|
||||
|
||||
```sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
```
|
||||
|
||||
* 如果 make build 在如下错误上停止:
|
||||
|
||||
```sh
|
||||
ModuleNotFoundError: no module named <module-name>
|
||||
```
|
||||
|
||||
这可能是 Poetry 缓存的问题。
|
||||
尝试依次运行这两个命令:
|
||||
|
||||
```sh
|
||||
rm -r ~/.cache/pypoetry
|
||||
make build
|
||||
```
|
||||
|
||||
---
|
||||
### NoneType 对象没有属性 'request'
|
||||
|
||||
如果您在执行 `make run` 时遇到与网络相关的问题,例如 `NoneType 对象没有属性 'request'`,您可能需要配置 WSL2 网络设置。请按照以下步骤操作:
|
||||
|
||||
* 在 Windows 主机上打开或创建位于 `C:\Users\%username%\.wslconfig` 的 `.wslconfig` 文件。
|
||||
* 将以下配置添加到 `.wslconfig` 文件中:
|
||||
|
||||
```sh
|
||||
[wsl2]
|
||||
networkingMode=mirrored
|
||||
localhostForwarding=true
|
||||
```
|
||||
|
||||
* 保存 `.wslconfig` 文件。
|
||||
* 通过退出任何正在运行的 WSL2 实例并在命令提示符或终端中执行 `wsl --shutdown` 命令来完全重启 WSL2。
|
||||
* 重新启动 WSL 后,再次尝试执行 `make run`。
|
||||
网络问题应该得到解决。
|
||||
@@ -50,7 +50,7 @@ LLM_API_KEY="sk_test_12345"
|
||||
```bash
|
||||
docker run -it \
|
||||
--pull=always \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.15-nikolaik \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.14-nikolaik \
|
||||
-e SANDBOX_USER_ID=$(id -u) \
|
||||
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
|
||||
-e LLM_API_KEY=$LLM_API_KEY \
|
||||
@@ -59,7 +59,7 @@ docker run -it \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
--add-host host.docker.internal:host-gateway \
|
||||
--name openhands-app-$(date +%Y%m%d%H%M%S) \
|
||||
docker.all-hands.dev/all-hands-ai/openhands:0.15 \
|
||||
docker.all-hands.dev/all-hands-ai/openhands:0.14 \
|
||||
python -m openhands.core.cli
|
||||
```
|
||||
|
||||
|
||||
@@ -37,15 +37,12 @@ the [README for the OpenHands Resolver](https://github.com/All-Hands-AI/OpenHand
|
||||
|
||||
You can provide custom directions for OpenHands by following the [README for the resolver](https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/resolver/README.md#providing-custom-instructions).
|
||||
|
||||
### Custom configurations
|
||||
### Configure custom macro
|
||||
|
||||
Github resolver will automatically check for valid [repository secrets](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions?tool=webui#creating-secrets-for-a-repository) or [repository variables](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#creating-configuration-variables-for-a-repository) to customize its behavior. The customization options you can set are:
|
||||
To customize the default macro (`@openhands-agent`):
|
||||
|
||||
| **Attribute name** | **Type** | **Purpose** | **Example** |
|
||||
| -------------------------------- | -------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
|
||||
| `OPENHANDS_MAX_ITER` | Variable | Set max limit for agent iterations | `OPENHANDS_MAX_ITER=10` |
|
||||
| `OPENHANDS_MACRO` | Variable | Customize default macro for invoking the resolver | `OPENHANDS_MACRO=@resolveit` |
|
||||
| `OPENHANDS_BASE_CONTAINER_IMAGE` | Variable | Custom Sandbox ([learn more](https://docs.all-hands.dev/modules/usage/how-to/custom-sandbox-guide)) | `OPENHANDS_BASE_CONTAINER_IMAGE="custom_image"` |
|
||||
1. [Create a repository variable](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#creating-configuration-variables-for-a-repository) named `OPENHANDS_MACRO`
|
||||
2. Assign the variable a custom value
|
||||
|
||||
## Writing Effective .openhands_instructions Files
|
||||
|
||||
@@ -58,7 +55,6 @@ The `.openhands_instructions` file is a file that you can put in the root direct
|
||||
2. **Repository Structure**: Explain the key directories and their purposes, especially highlighting where different types of code (e.g., frontend, backend) are located.
|
||||
|
||||
3. **Development Workflows**: Document the essential commands for:
|
||||
|
||||
- Building and setting up the project
|
||||
- Running tests
|
||||
- Linting and code quality checks
|
||||
@@ -73,29 +69,24 @@ The `.openhands_instructions` file is a file that you can put in the root direct
|
||||
|
||||
```markdown
|
||||
# Repository Overview
|
||||
|
||||
[Brief description of the project]
|
||||
|
||||
## General Setup
|
||||
|
||||
- Main build command
|
||||
- Development environment setup
|
||||
- Pre-commit checks
|
||||
|
||||
## Backend
|
||||
|
||||
- Location and structure
|
||||
- Testing instructions
|
||||
- Environment requirements
|
||||
|
||||
## Frontend
|
||||
|
||||
- Setup prerequisites
|
||||
- Build and test commands
|
||||
- Environment variables
|
||||
|
||||
## Additional Guidelines
|
||||
|
||||
- Code style requirements
|
||||
- Special considerations
|
||||
- Common workflows
|
||||
|
||||
@@ -23,75 +23,10 @@ OpenHands provides a user-friendly Graphical User Interface (GUI) mode for inter
|
||||
|
||||
OpenHands automatically exports a `GITHUB_TOKEN` to the shell environment if it is available. This can happen in two ways:
|
||||
|
||||
1. **Locally (OSS)**: The user directly inputs their GitHub token
|
||||
2. **Online (SaaS)**: The token is obtained through GitHub OAuth authentication
|
||||
1. Locally (OSS): The user directly inputs their GitHub token.
|
||||
2. Online (SaaS): The token is obtained through GitHub OAuth authentication.
|
||||
|
||||
#### Setting Up a Local GitHub Token
|
||||
|
||||
1. **Generate a Personal Access Token (PAT)**:
|
||||
- Go to GitHub Settings > Developer Settings > Personal Access Tokens > Tokens (classic)
|
||||
- Click "Generate new token (classic)"
|
||||
- Required scopes:
|
||||
- `repo` (Full control of private repositories)
|
||||
- `workflow` (Update GitHub Action workflows)
|
||||
- `read:org` (Read organization data)
|
||||
|
||||
2. **Enter Token in OpenHands**:
|
||||
- Click the Settings button (gear icon) in the top right
|
||||
- Navigate to the "GitHub" section
|
||||
- Paste your token in the "GitHub Token" field
|
||||
- Click "Save" to apply the changes
|
||||
|
||||
#### Organizational Token Policies
|
||||
|
||||
If you're working with organizational repositories, additional setup may be required:
|
||||
|
||||
1. **Check Organization Requirements**:
|
||||
- Organization admins may enforce specific token policies
|
||||
- Some organizations require tokens to be created with SSO enabled
|
||||
- Review your organization's [token policy settings](https://docs.github.com/en/organizations/managing-programmatic-access-to-your-organization/setting-a-personal-access-token-policy-for-your-organization)
|
||||
|
||||
2. **Verify Organization Access**:
|
||||
- Go to your token settings on GitHub
|
||||
- Look for the organization under "Organization access"
|
||||
- If required, click "Enable SSO" next to your organization
|
||||
- Complete the SSO authorization process
|
||||
|
||||
#### OAuth Authentication (Online Mode)
|
||||
|
||||
When using OpenHands in online mode, the GitHub OAuth flow:
|
||||
|
||||
1. Requests the following permissions:
|
||||
- Repository access (read/write)
|
||||
- Workflow management
|
||||
- Organization read access
|
||||
|
||||
2. Authentication steps:
|
||||
- Click "Sign in with GitHub" when prompted
|
||||
- Review the requested permissions
|
||||
- Authorize OpenHands to access your GitHub account
|
||||
- If using an organization, authorize organization access if prompted
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
Common issues and solutions:
|
||||
|
||||
1. **Token Not Recognized**:
|
||||
- Ensure the token is properly saved in settings
|
||||
- Check that the token hasn't expired
|
||||
- Verify the token has the required scopes
|
||||
- Try regenerating the token
|
||||
|
||||
2. **Organization Access Denied**:
|
||||
- Check if SSO is required but not enabled
|
||||
- Verify organization membership
|
||||
- Contact organization admin if token policies are blocking access
|
||||
|
||||
3. **Verifying Token Works**:
|
||||
- The app will show a green checkmark if the token is valid
|
||||
- Try accessing a repository to confirm permissions
|
||||
- Check the browser console for any error messages
|
||||
- Use the "Test Connection" button in settings if available
|
||||
When you reach the `/app` route, the app checks if a token is present. If it finds one, it sets it in the environment for the agent to use.
|
||||
|
||||
### Advanced Settings
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ LLM_API_KEY="sk_test_12345"
|
||||
```bash
|
||||
docker run -it \
|
||||
--pull=always \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.15-nikolaik \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.14-nikolaik \
|
||||
-e SANDBOX_USER_ID=$(id -u) \
|
||||
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
|
||||
-e LLM_API_KEY=$LLM_API_KEY \
|
||||
@@ -54,6 +54,6 @@ docker run -it \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
--add-host host.docker.internal:host-gateway \
|
||||
--name openhands-app-$(date +%Y%m%d%H%M%S) \
|
||||
docker.all-hands.dev/all-hands-ai/openhands:0.15 \
|
||||
python -m openhands.core.main -t "write a bash script that prints hi" --no-auto-continue
|
||||
docker.all-hands.dev/all-hands-ai/openhands:0.14 \
|
||||
python -m openhands.core.main -t "write a bash script that prints hi"
|
||||
```
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# Persisting Session Data
|
||||
|
||||
Using the standard installation, the session data is stored in memory. Currently, if OpenHands' service is restarted,
|
||||
previous sessions become invalid (a new secret is generated) and thus not recoverable.
|
||||
|
||||
## How to Persist Session Data
|
||||
|
||||
### Development Workflow
|
||||
In the `config.toml` file, specify the following:
|
||||
```
|
||||
[core]
|
||||
...
|
||||
file_store="local"
|
||||
file_store_path="/absolute/path/to/openhands/cache/directory"
|
||||
jwt_secret="secretpass"
|
||||
```
|
||||
@@ -11,16 +11,16 @@
|
||||
The easiest way to run OpenHands is in Docker.
|
||||
|
||||
```bash
|
||||
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.15-nikolaik
|
||||
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.14-nikolaik
|
||||
|
||||
docker run -it --rm --pull=always \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.15-nikolaik \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.14-nikolaik \
|
||||
-e LOG_ALL_EVENTS=true \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-p 3000:3000 \
|
||||
--add-host host.docker.internal:host-gateway \
|
||||
--name openhands-app \
|
||||
docker.all-hands.dev/all-hands-ai/openhands:0.15
|
||||
docker.all-hands.dev/all-hands-ai/openhands:0.14
|
||||
```
|
||||
|
||||
You can also run OpenHands in a scriptable [headless mode](https://docs.all-hands.dev/modules/usage/how-to/headless-mode), as an [interactive CLI](https://docs.all-hands.dev/modules/usage/how-to/cli-mode), or using the [OpenHands GitHub Action](https://docs.all-hands.dev/modules/usage/how-to/github-action).
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
# Micro-Agents
|
||||
|
||||
OpenHands uses specialized micro-agents to handle specific tasks and contexts efficiently. These micro-agents are small, focused components that provide specialized behavior and knowledge for particular scenarios.
|
||||
|
||||
## Overview
|
||||
|
||||
Micro-agents are defined in markdown files under the `openhands/agenthub/codeact_agent/micro/` directory. Each micro-agent is configured with:
|
||||
|
||||
- A unique name
|
||||
- The agent type (typically CodeActAgent)
|
||||
- Trigger keywords that activate the agent
|
||||
- Specific instructions and capabilities
|
||||
|
||||
## Available Micro-Agents
|
||||
|
||||
### GitHub Agent
|
||||
**File**: `github.md`
|
||||
**Triggers**: `github`, `git`
|
||||
|
||||
The GitHub agent specializes in GitHub API interactions and repository management. It:
|
||||
- Has access to a `GITHUB_TOKEN` for API authentication
|
||||
- Follows strict guidelines for repository interactions
|
||||
- Handles branch management and pull requests
|
||||
- Uses the GitHub API instead of web browser interactions
|
||||
|
||||
Key features:
|
||||
- Branch protection (prevents direct pushes to main/master)
|
||||
- Automated PR creation
|
||||
- Git configuration management
|
||||
- API-first approach for GitHub operations
|
||||
|
||||
### NPM Agent
|
||||
**File**: `npm.md`
|
||||
**Triggers**: `npm`
|
||||
|
||||
Specializes in handling npm package management with specific focus on:
|
||||
- Non-interactive shell operations
|
||||
- Automated confirmation handling using Unix 'yes' command
|
||||
- Package installation automation
|
||||
|
||||
### Custom Micro-Agents
|
||||
|
||||
You can create your own micro-agents by adding new markdown files to the micro-agents directory. Each file should follow this structure:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: agent_name
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- trigger_word1
|
||||
- trigger_word2
|
||||
---
|
||||
|
||||
Instructions and capabilities for the micro-agent...
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
When working with micro-agents:
|
||||
|
||||
1. **Use Appropriate Triggers**: Ensure your commands include the relevant trigger words to activate the correct micro-agent
|
||||
2. **Follow Agent Guidelines**: Each agent has specific instructions and limitations - respect these for optimal results
|
||||
3. **API-First Approach**: When available, use API endpoints rather than web interfaces
|
||||
4. **Automation Friendly**: Design commands that work well in non-interactive environments
|
||||
|
||||
## Integration
|
||||
|
||||
Micro-agents are automatically integrated into OpenHands' workflow. They:
|
||||
- Monitor incoming commands for their trigger words
|
||||
- Activate when relevant triggers are detected
|
||||
- Apply their specialized knowledge and capabilities
|
||||
- Follow their specific guidelines and restrictions
|
||||
|
||||
## Example Usage
|
||||
|
||||
```bash
|
||||
# GitHub agent example
|
||||
git checkout -b feature-branch
|
||||
git commit -m "Add new feature"
|
||||
git push origin feature-branch
|
||||
|
||||
# NPM agent example
|
||||
yes | npm install package-name
|
||||
```
|
||||
|
||||
For more information about specific agents, refer to their individual documentation files in the micro-agents directory.
|
||||
|
||||
## Contributing a Micro-Agent
|
||||
|
||||
To contribute a new micro-agent to OpenHands, follow these guidelines:
|
||||
|
||||
### 1. Planning Your Micro-Agent
|
||||
|
||||
Before creating a micro-agent, consider:
|
||||
- What specific problem or use case will it address?
|
||||
- What unique capabilities or knowledge should it have?
|
||||
- What trigger words make sense for activating it?
|
||||
- What constraints or guidelines should it follow?
|
||||
|
||||
### 2. File Structure
|
||||
|
||||
Create a new markdown file in `openhands/agenthub/codeact_agent/micro/` with a descriptive name (e.g., `docker.md` for a Docker-focused agent).
|
||||
|
||||
### 3. Required Components
|
||||
|
||||
Your micro-agent file must include:
|
||||
|
||||
1. **Front Matter**: YAML metadata at the start of the file:
|
||||
```markdown
|
||||
---
|
||||
name: your_agent_name
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- trigger_word1
|
||||
- trigger_word2
|
||||
---
|
||||
```
|
||||
|
||||
2. **Instructions**: Clear, specific guidelines for the agent's behavior:
|
||||
```markdown
|
||||
You are responsible for [specific task/domain].
|
||||
|
||||
Key responsibilities:
|
||||
1. [Responsibility 1]
|
||||
2. [Responsibility 2]
|
||||
|
||||
Guidelines:
|
||||
- [Guideline 1]
|
||||
- [Guideline 2]
|
||||
|
||||
Examples of usage:
|
||||
[Example 1]
|
||||
[Example 2]
|
||||
```
|
||||
|
||||
### 4. Best Practices for Micro-Agent Development
|
||||
|
||||
1. **Clear Scope**: Keep the agent focused on a specific domain or task
|
||||
2. **Explicit Instructions**: Provide clear, unambiguous guidelines
|
||||
3. **Useful Examples**: Include practical examples of common use cases
|
||||
4. **Safety First**: Include necessary warnings and constraints
|
||||
5. **Integration Awareness**: Consider how the agent interacts with other components
|
||||
|
||||
### 5. Testing Your Micro-Agent
|
||||
|
||||
Before submitting:
|
||||
1. Test the agent with various prompts
|
||||
2. Verify trigger words activate the agent correctly
|
||||
3. Ensure instructions are clear and comprehensive
|
||||
4. Check for potential conflicts with existing agents
|
||||
|
||||
### 6. Example Implementation
|
||||
|
||||
Here's a template for a new micro-agent:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: docker
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- docker
|
||||
- container
|
||||
---
|
||||
|
||||
You are responsible for Docker container management and Dockerfile creation.
|
||||
|
||||
Key responsibilities:
|
||||
1. Create and modify Dockerfiles
|
||||
2. Manage container lifecycle
|
||||
3. Handle Docker Compose configurations
|
||||
|
||||
Guidelines:
|
||||
- Always use official base images when possible
|
||||
- Include necessary security considerations
|
||||
- Follow Docker best practices for layer optimization
|
||||
|
||||
Examples:
|
||||
1. Creating a Dockerfile:
|
||||
```dockerfile
|
||||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
CMD ["npm", "start"]
|
||||
```
|
||||
|
||||
2. Docker Compose usage:
|
||||
```yaml
|
||||
version: '3'
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
ports:
|
||||
- "3000:3000"
|
||||
```
|
||||
|
||||
Remember to:
|
||||
- Validate Dockerfile syntax
|
||||
- Check for security vulnerabilities
|
||||
- Optimize for build time and image size
|
||||
```
|
||||
|
||||
### 7. Submission Process
|
||||
|
||||
1. Create your micro-agent file in the correct directory
|
||||
2. Test thoroughly
|
||||
3. Submit a pull request with:
|
||||
- The new micro-agent file
|
||||
- Updated documentation if needed
|
||||
- Description of the agent's purpose and capabilities
|
||||
|
||||
Remember that micro-agents are a powerful way to extend OpenHands' capabilities in specific domains. Well-designed agents can significantly improve the system's ability to handle specialized tasks.
|
||||
@@ -2,11 +2,6 @@
|
||||
|
||||
When working with OpenHands AI software developer, it's crucial to provide clear and effective prompts. This guide outlines best practices for creating prompts that will yield the most accurate and useful responses.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Characteristics of Good Prompts](#characteristics-of-good-prompts)
|
||||
- [Customizing Prompts for your Project](#customizing-prompts-for-your-project)
|
||||
|
||||
## Characteristics of Good Prompts
|
||||
|
||||
Good prompts are:
|
||||
@@ -44,63 +39,3 @@ Good prompts are:
|
||||
Remember, the more precise and informative your prompt is, the better the AI can assist you in developing or modifying the OpenHands software.
|
||||
|
||||
See [Getting Started with OpenHands](./getting-started) for more examples of helpful prompts.
|
||||
|
||||
## Customizing Prompts for your Project
|
||||
|
||||
OpenHands can be customized to work more effectively with specific repositories by providing repository-specific context and guidelines. This section explains how to optimize OpenHands for your project.
|
||||
|
||||
### Repository Configuration
|
||||
|
||||
You can customize OpenHands' behavior for your repository by creating a `.openhands_instructions` file in your repository's root directory. This file should contain:
|
||||
|
||||
1. **Repository Overview**: A brief description of your project's purpose and architecture
|
||||
2. **Directory Structure**: Key directories and their purposes
|
||||
3. **Development Guidelines**: Project-specific coding standards and practices
|
||||
4. **Testing Requirements**: How to run tests and what types of tests are required
|
||||
5. **Setup Instructions**: Steps needed to build and run the project
|
||||
|
||||
Example `.openhands_instructions` file:
|
||||
```
|
||||
Repository: MyProject
|
||||
Description: A web application for task management
|
||||
|
||||
Directory Structure:
|
||||
- src/: Main application code
|
||||
- tests/: Test files
|
||||
- docs/: Documentation
|
||||
|
||||
Setup:
|
||||
- Run `npm install` to install dependencies
|
||||
- Use `npm run dev` for development
|
||||
- Run `npm test` for testing
|
||||
|
||||
Guidelines:
|
||||
- Follow ESLint configuration
|
||||
- Write tests for all new features
|
||||
- Use TypeScript for new code
|
||||
```
|
||||
|
||||
### Customizing Prompts
|
||||
|
||||
When working with a customized repository:
|
||||
|
||||
1. **Reference Project Standards**: Mention specific coding standards or patterns used in your project
|
||||
2. **Include Context**: Reference relevant documentation or existing implementations
|
||||
3. **Specify Testing Requirements**: Include project-specific testing requirements in your prompts
|
||||
|
||||
Example customized prompt:
|
||||
```
|
||||
Add a new task completion feature to src/components/TaskList.tsx following our existing component patterns.
|
||||
Include unit tests in tests/components/ and update the documentation in docs/features/.
|
||||
The component should use our shared styling from src/styles/components.
|
||||
```
|
||||
|
||||
### Best Practices for Repository Customization
|
||||
|
||||
1. **Keep Instructions Updated**: Regularly update your `.openhands_instructions` file as your project evolves
|
||||
2. **Be Specific**: Include specific paths, patterns, and requirements unique to your project
|
||||
3. **Document Dependencies**: List all tools and dependencies required for development
|
||||
4. **Include Examples**: Provide examples of good code patterns from your project
|
||||
5. **Specify Conventions**: Document naming conventions, file organization, and code style preferences
|
||||
|
||||
By customizing OpenHands for your repository, you'll get more accurate and consistent results that align with your project's standards and requirements.
|
||||
|
||||
@@ -16,7 +16,7 @@ some flags being passed to `docker run` that make this possible:
|
||||
|
||||
```
|
||||
docker run # ...
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.15-nikolaik \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.11-nikolaik \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -1,44 +1,180 @@
|
||||
# 🚧 Troubleshooting
|
||||
|
||||
There are some error messages that frequently get reported by users.
|
||||
We'll try to make the install process easier, but for now you can look for your error message below and see if there are any workarounds.
|
||||
If you find more information or a workaround for one of these issues, please open a *PR* to add details to this file.
|
||||
|
||||
:::tip
|
||||
OpenHands only supports Windows via WSL. Please be sure to run all commands inside your WSL terminal.
|
||||
OpenHands only supports Windows via [WSL](https://learn.microsoft.com/en-us/windows/wsl/install).
|
||||
Please be sure to run all commands inside your WSL terminal.
|
||||
Check out [Notes for WSL on Windows Users](troubleshooting/windows) for some troubleshooting guides.
|
||||
:::
|
||||
|
||||
### Launch docker client failed
|
||||
## Common Issues
|
||||
|
||||
**Description**
|
||||
* [Unable to connect to Docker](#unable-to-connect-to-docker)
|
||||
* [404 Resource not found](#404-resource-not-found)
|
||||
* [`make build` getting stuck on package installations](#make-build-getting-stuck-on-package-installations)
|
||||
* [Sessions are not restored](#sessions-are-not-restored)
|
||||
* [Connection to host.docker.internal timed out](#connection-to-host-docker-internal-timed-out)
|
||||
|
||||
When running OpenHands, the following error is seen:
|
||||
```
|
||||
Launch docker client failed. Please make sure you have installed docker and started docker desktop/daemon.
|
||||
### Unable to connect to Docker
|
||||
|
||||
[GitHub Issue](https://github.com/All-Hands-AI/OpenHands/issues/1226)
|
||||
|
||||
**Symptoms**
|
||||
|
||||
```bash
|
||||
Error creating controller. Please check Docker is running and visit `https://docs.all-hands.dev/modules/usage/troubleshooting` for more debugging information.
|
||||
```
|
||||
|
||||
**Resolution**
|
||||
```bash
|
||||
docker.errors.DockerException: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))
|
||||
```
|
||||
|
||||
**Details**
|
||||
|
||||
OpenHands uses a Docker container to do its work safely, without potentially breaking your machine.
|
||||
|
||||
**Workarounds**
|
||||
|
||||
* Run `docker ps` to ensure that docker is running
|
||||
* Make sure you don't need `sudo` to run docker [see here](https://www.baeldung.com/linux/docker-run-without-sudo)
|
||||
* If you are on a Mac, check the [permissions requirements](https://docs.docker.com/desktop/mac/permission-requirements/) and in particular consider enabling the `Allow the default Docker socket to be used` under `Settings > Advanced` in Docker Desktop.
|
||||
* In addition, upgrade your Docker to the latest version under `Check for Updates`
|
||||
|
||||
Try these in order:
|
||||
* Confirm `docker` is running on your system. You should be able to run `docker ps` in the terminal successfully.
|
||||
* If using Docker Desktop, ensure `Settings > Advanced > Allow the default Docker socket to be used` is enabled.
|
||||
* Depending on your configuration you may need `Settings > Resources > Network > Enable host networking` enabled in Docker Desktop.
|
||||
* Reinstall Docker Desktop.
|
||||
---
|
||||
### `404 Resource not found`
|
||||
|
||||
# Development Workflow Specific
|
||||
### Error building runtime docker image
|
||||
**Symptoms**
|
||||
|
||||
**Description**
|
||||
|
||||
Attempts to start a new session fail, and errors with terms like the following appear in the logs:
|
||||
```
|
||||
debian-security bookworm-security
|
||||
InRelease At least one invalid signature was encountered.
|
||||
```python
|
||||
Traceback (most recent call last):
|
||||
File "/app/.venv/lib/python3.12/site-packages/litellm/llms/openai.py", line 414, in completion
|
||||
raise e
|
||||
File "/app/.venv/lib/python3.12/site-packages/litellm/llms/openai.py", line 373, in completion
|
||||
response = openai_client.chat.completions.create(**data, timeout=timeout) # type: ignore
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/.venv/lib/python3.12/site-packages/openai/_utils/_utils.py", line 277, in wrapper
|
||||
return func(*args, **kwargs)
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/.venv/lib/python3.12/site-packages/openai/resources/chat/completions.py", line 579, in create
|
||||
return self._post(
|
||||
^^^^^^^^^^^
|
||||
File "/app/.venv/lib/python3.12/site-packages/openai/_base_client.py", line 1232, in post
|
||||
return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/.venv/lib/python3.12/site-packages/openai/_base_client.py", line 921, in request
|
||||
return self._request(
|
||||
^^^^^^^^^^^^^^
|
||||
File "/app/.venv/lib/python3.12/site-packages/openai/_base_client.py", line 1012, in _request
|
||||
raise self._make_status_error_from_response(err.response) from None
|
||||
openai.NotFoundError: Error code: 404 - {'error': {'code': '404', 'message': 'Resource not found'}}
|
||||
```
|
||||
|
||||
This seems to happen when the hash of an existing external library changes and your local docker instance has
|
||||
cached a previous version. To work around this, please try the following:
|
||||
**Details**
|
||||
|
||||
* Stop any containers where the name has the prefix `openhands-runtime-` :
|
||||
`docker ps --filter name=openhands-runtime- --filter status=running -aq | xargs docker stop`
|
||||
* Remove any containers where the name has the prefix `openhands-runtime-` :
|
||||
`docker rmi $(docker images --filter name=openhands-runtime- -q --no-trunc)`
|
||||
* Stop and Remove any containers / images where the name has the prefix `openhands-runtime-`
|
||||
* Prune containers / images : `docker container prune -f && docker image prune -f`
|
||||
This happens when LiteLLM (our library for connecting to different LLM providers) can't find
|
||||
the API endpoint you're trying to connect to. Most often this happens for Azure or ollama users.
|
||||
|
||||
**Workarounds**
|
||||
|
||||
* Check that you've set `LLM_BASE_URL` properly
|
||||
* Check that the model is set properly, based on the [LiteLLM docs](https://docs.litellm.ai/docs/providers)
|
||||
* If you're running inside the UI, be sure to set the `model` in the settings modal
|
||||
* If you're running headless (via main.py) be sure to set `LLM_MODEL` in your env/config
|
||||
* Make sure you've followed any special instructions for your LLM provider
|
||||
* [Azure](/modules/usage/llms/azure-llms)
|
||||
* [Google](/modules/usage/llms/google-llms)
|
||||
* Make sure your API key is correct
|
||||
* See if you can connect to the LLM using `curl`
|
||||
* Try [connecting via LiteLLM directly](https://github.com/BerriAI/litellm) to test your setup
|
||||
|
||||
---
|
||||
### `make build` getting stuck on package installations
|
||||
|
||||
**Symptoms**
|
||||
|
||||
Package installation stuck on `Pending...` without any error message:
|
||||
|
||||
```bash
|
||||
Package operations: 286 installs, 0 updates, 0 removals
|
||||
|
||||
- Installing certifi (2024.2.2): Pending...
|
||||
- Installing h11 (0.14.0): Pending...
|
||||
- Installing idna (3.7): Pending...
|
||||
- Installing sniffio (1.3.1): Pending...
|
||||
- Installing typing-extensions (4.11.0): Pending...
|
||||
```
|
||||
|
||||
**Details**
|
||||
|
||||
In rare cases, `make build` can seemingly get stuck on package installations
|
||||
without any error message.
|
||||
|
||||
**Workarounds**
|
||||
|
||||
The package installer Poetry may miss a configuration setting for where credentials are to be looked up (keyring).
|
||||
|
||||
First check with `env` if a value for `PYTHON_KEYRING_BACKEND` exists.
|
||||
If not, run the below command to set it to a known value and retry the build:
|
||||
|
||||
```bash
|
||||
export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring
|
||||
```
|
||||
|
||||
---
|
||||
### Sessions are not restored
|
||||
|
||||
**Symptoms**
|
||||
|
||||
OpenHands usually asks whether to resume or start a new session when opening the UI.
|
||||
But clicking "Resume" still starts a fresh new chat.
|
||||
|
||||
**Details**
|
||||
|
||||
With a standard installation as of today session data is stored in memory.
|
||||
Currently, if OpenHands's service is restarted, previous sessions become
|
||||
invalid (a new secret is generated) and thus not recoverable.
|
||||
|
||||
**Workarounds**
|
||||
|
||||
* Change configuration to make sessions persistent by editing the `config.toml`
|
||||
file (in OpenHands's root folder) by specifying a `file_store` and an
|
||||
absolute `file_store_path`:
|
||||
|
||||
```toml
|
||||
file_store="local"
|
||||
file_store_path="/absolute/path/to/openhands/cache/directory"
|
||||
```
|
||||
|
||||
* Add a fixed jwt secret in your .bashrc, like below, so that previous session id's
|
||||
should stay accepted.
|
||||
|
||||
```bash
|
||||
EXPORT JWT_SECRET=A_CONST_VALUE
|
||||
```
|
||||
|
||||
---
|
||||
### Connection to host docker internal timed out
|
||||
|
||||
**Symptoms**
|
||||
|
||||
When you start the server using the docker command from the main [README](https://github.com/All-Hands-AI/OpenHands/README.md), you get a long timeout
|
||||
followed by the a stack trace containing messages like:
|
||||
|
||||
* `Connection to host.docker.internal timed out. (connect timeout=310)`
|
||||
* `Max retries exceeded with url: /alive`
|
||||
|
||||
**Details**
|
||||
|
||||
If Docker Engine is installed rather than Docker Desktop, the main command will not work as expected.
|
||||
Docker Desktop includes easy DNS configuration for connecting processes running in different containers
|
||||
which OpenHands makes use of when the main server is running inside a docker container.
|
||||
(Further details: https://forums.docker.com/t/difference-between-docker-desktop-and-docker-engine/124612)
|
||||
|
||||
**Workarounds**
|
||||
|
||||
* [Install Docker Desktop](https://www.docker.com/products/docker-desktop/)
|
||||
* Run OpenHands in [Development Mode](https://github.com/All-Hands-AI/OpenHands/blob/main/Development.md),
|
||||
So that the main server is not run inside a container, but still creates dockerized runtime sandboxes.
|
||||
|
||||
64
docs/modules/usage/troubleshooting/windows.md
Normal file
64
docs/modules/usage/troubleshooting/windows.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Notes for WSL on Windows Users
|
||||
|
||||
OpenHands only supports Windows via [WSL](https://learn.microsoft.com/en-us/windows/wsl/install).
|
||||
Please be sure to run all commands inside your WSL terminal.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Recommendation: Do not run as root user
|
||||
|
||||
For security reasons, it is highly recommended to not run OpenHands as the root user, but a user with a non-zero UID.
|
||||
|
||||
References:
|
||||
|
||||
* [Why it is bad to login as root](https://askubuntu.com/questions/16178/why-is-it-bad-to-log-in-as-root)
|
||||
* [Set default user in WSL](https://www.tenforums.com/tutorials/128152-set-default-user-windows-subsystem-linux-distro-windows-10-a.html#option2)
|
||||
Hint about the 2nd reference: for Ubuntu users, the command could actually be "ubuntupreview" instead of "ubuntu".
|
||||
|
||||
---
|
||||
### Error: 'docker' could not be found in this WSL 2 distro.
|
||||
|
||||
If you are using Docker Desktop, make sure to start it before calling any docker command from inside WSL.
|
||||
Docker also needs to have the WSL integration option activated.
|
||||
|
||||
---
|
||||
### Poetry Installation
|
||||
|
||||
* If you face issues running Poetry even after installing it during the build process, you may need to add its binary path to your environment:
|
||||
|
||||
```sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
```
|
||||
|
||||
* If make build stops on an error like this:
|
||||
|
||||
```sh
|
||||
ModuleNotFoundError: no module named <module-name>
|
||||
```
|
||||
|
||||
This could be an issue with Poetry's cache.
|
||||
Try to run these 2 commands after another:
|
||||
|
||||
```sh
|
||||
rm -r ~/.cache/pypoetry
|
||||
make build
|
||||
```
|
||||
|
||||
---
|
||||
### NoneType object has no attribute 'request'
|
||||
|
||||
If you are experiencing issues related to networking, such as `NoneType object has no attribute 'request'` when executing `make run`, you may need to configure your WSL2 networking settings. Follow these steps:
|
||||
|
||||
* Open or create the `.wslconfig` file located at `C:\Users\%username%\.wslconfig` on your Windows host machine.
|
||||
* Add the following configuration to the `.wslconfig` file:
|
||||
|
||||
```sh
|
||||
[wsl2]
|
||||
networkingMode=mirrored
|
||||
localhostForwarding=true
|
||||
```
|
||||
|
||||
* Save the `.wslconfig` file.
|
||||
* Restart WSL2 completely by exiting any running WSL2 instances and executing the command `wsl --shutdown` in your command prompt or terminal.
|
||||
* After restarting WSL, attempt to execute `make run` again.
|
||||
The networking issue should be resolved.
|
||||
71
docs/modules/usage/upgrade-guide.md
Normal file
71
docs/modules/usage/upgrade-guide.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# ⬆️ Upgrade Guide
|
||||
|
||||
## 0.8.0 (2024-07-13)
|
||||
|
||||
### Config breaking changes
|
||||
|
||||
In this release we introduced a few breaking changes to backend configurations.
|
||||
If you have only been using OpenHands via frontend (web GUI), nothing needs
|
||||
to be taken care of.
|
||||
|
||||
Here's a list of breaking changes in configs. They only apply to users who
|
||||
use OpenHands CLI via `main.py`. For more detail, see [#2756](https://github.com/All-Hands-AI/OpenHands/pull/2756).
|
||||
|
||||
#### Removal of --model-name option from main.py
|
||||
|
||||
Please note that `--model-name`, or `-m` option, no longer exists. You should set up the LLM
|
||||
configs in `config.toml` or via environmental variables.
|
||||
|
||||
#### LLM config groups must be subgroups of 'llm'
|
||||
|
||||
Prior to release 0.8, you can use arbitrary name for llm config in `config.toml`, e.g.
|
||||
|
||||
```toml
|
||||
[gpt-4o]
|
||||
model="gpt-4o"
|
||||
api_key="<your_api_key>"
|
||||
```
|
||||
|
||||
and then use `--llm-config` CLI argument to specify the desired LLM config group
|
||||
by name. This no longer works. Instead, the config group must be under `llm` group,
|
||||
e.g.:
|
||||
|
||||
```toml
|
||||
[llm.gpt-4o]
|
||||
model="gpt-4o"
|
||||
api_key="<your_api_key>"
|
||||
```
|
||||
|
||||
If you have a config group named `llm`, no need to change it, it will be used
|
||||
as the default LLM config group.
|
||||
|
||||
#### 'agent' group no longer contains 'name' field
|
||||
|
||||
Prior to release 0.8, you may or may not have a config group named `agent` that
|
||||
looks like this:
|
||||
|
||||
```toml
|
||||
[agent]
|
||||
name="CodeActAgent"
|
||||
memory_max_threads=2
|
||||
```
|
||||
|
||||
Note the `name` field is now removed. Instead, you should put `default_agent` field
|
||||
under `core` group, e.g.
|
||||
|
||||
```toml
|
||||
[core]
|
||||
# other configs
|
||||
default_agent='CodeActAgent'
|
||||
|
||||
[agent]
|
||||
llm_config='llm'
|
||||
memory_max_threads=2
|
||||
|
||||
[agent.CodeActAgent]
|
||||
llm_config='gpt-4o'
|
||||
```
|
||||
|
||||
Note that similar to `llm` subgroups, you can also define `agent` subgroups.
|
||||
Moreover, an agent can be associated with a specific LLM config group. For more
|
||||
detail, see the examples in `config.template.toml`.
|
||||
26
docs/package-lock.json
generated
26
docs/package-lock.json
generated
@@ -17,14 +17,14 @@
|
||||
"prism-react-renderer": "^2.4.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-use": "^17.6.0"
|
||||
"react-icons": "^5.3.0",
|
||||
"react-use": "^17.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^3.5.1",
|
||||
"@docusaurus/tsconfig": "^3.6.3",
|
||||
"@docusaurus/types": "^3.5.1",
|
||||
"typescript": "~5.7.2"
|
||||
"typescript": "~5.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0"
|
||||
@@ -15155,10 +15155,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz",
|
||||
"integrity": "sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==",
|
||||
"license": "MIT",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz",
|
||||
"integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
@@ -15264,9 +15263,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-use": {
|
||||
"version": "17.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-use/-/react-use-17.6.0.tgz",
|
||||
"integrity": "sha512-OmedEScUMKFfzn1Ir8dBxiLLSOzhKe/dPZwVxcujweSj45aNM7BEGPb9BEVIgVEqEXx6f3/TsXzwIktNgUR02g==",
|
||||
"version": "17.5.1",
|
||||
"resolved": "https://registry.npmjs.org/react-use/-/react-use-17.5.1.tgz",
|
||||
"integrity": "sha512-LG/uPEVRflLWMwi3j/sZqR00nF6JGqTTDblkXK2nzXsIvij06hXl1V/MZIlwj1OKIQUtlh1l9jK8gLsRyCQxMg==",
|
||||
"dependencies": {
|
||||
"@types/js-cookie": "^2.2.6",
|
||||
"@xobotyi/scrollbar-width": "^1.9.5",
|
||||
@@ -16986,10 +16985,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
|
||||
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
|
||||
"license": "Apache-2.0",
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
|
||||
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
"prism-react-renderer": "^2.4.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-use": "^17.6.0"
|
||||
"react-icons": "^5.3.0",
|
||||
"react-use": "^17.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^3.5.1",
|
||||
"@docusaurus/tsconfig": "^3.6.3",
|
||||
"@docusaurus/types": "^3.5.1",
|
||||
"typescript": "~5.7.2"
|
||||
"typescript": "~5.6.3"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@@ -14,20 +14,9 @@ const sidebars: SidebarsConfig = {
|
||||
id: 'usage/getting-started',
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Prompting',
|
||||
items: [
|
||||
{
|
||||
type: 'doc',
|
||||
label: 'Best Practices',
|
||||
id: 'usage/prompting-best-practices',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
label: 'Micro-Agents',
|
||||
id: 'usage/micro-agents',
|
||||
},
|
||||
],
|
||||
type: 'doc',
|
||||
label: 'Prompting Best Practices',
|
||||
id: 'usage/prompting-best-practices',
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
@@ -121,11 +110,6 @@ const sidebars: SidebarsConfig = {
|
||||
label: 'Custom Sandbox',
|
||||
id: 'usage/how-to/custom-sandbox-guide',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
label: 'Persist Session Data',
|
||||
id: 'usage/how-to/persist-session-data',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ function CustomFooter() {
|
||||
<footer className="custom-footer">
|
||||
<div className="footer-content">
|
||||
<div className="footer-icons">
|
||||
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2vbfigwev-G03twSpXaErwzYVD4CFiBg" target="_blank" rel="noopener noreferrer">
|
||||
<a href="https://join.slack.com/t/opendevin/shared_invite/zt-2oikve2hu-UDxHeo8nsE69y6T7yFX_BA" target="_blank" rel="noopener noreferrer">
|
||||
<FaSlack />
|
||||
</a>
|
||||
<a href="https://discord.gg/ESHStjSjD4" target="_blank" rel="noopener noreferrer">
|
||||
|
||||
@@ -23,7 +23,7 @@ export function HomepageHeader() {
|
||||
<a href="https://codecov.io/github/All-Hands-AI/OpenHands?branch=main"><img alt="CodeCov" src="https://img.shields.io/codecov/c/github/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" /></a>
|
||||
<a href="https://github.com/All-Hands-AI/OpenHands/blob/main/LICENSE"><img src="https://img.shields.io/github/license/All-Hands-AI/OpenHands?style=for-the-badge&color=blue" alt="MIT License" /></a>
|
||||
<br/>
|
||||
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2vbfigwev-G03twSpXaErwzYVD4CFiBg"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community" /></a>
|
||||
<a href="https://join.slack.com/t/openhands-ai/shared_invite/zt-2tom0er4l-JeNUGHt_AxpEfIBstbLPiw"><img src="https://img.shields.io/badge/Slack-Join%20Us-red?logo=slack&logoColor=white&style=for-the-badge" alt="Join our Slack community" /></a>
|
||||
<a href="https://discord.gg/ESHStjSjD4"><img src="https://img.shields.io/badge/Discord-Join%20Us-purple?logo=discord&logoColor=white&style=for-the-badge" alt="Join our Discord community" /></a>
|
||||
<a href="https://github.com/All-Hands-AI/OpenHands/blob/main/CREDITS.md"><img src="https://img.shields.io/badge/Project-Credits-blue?style=for-the-badge&color=FFE165&logo=github&logoColor=white" alt="Credits" /></a>
|
||||
<br/>
|
||||
|
||||
10172
docs/yarn.lock
Normal file
10172
docs/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,10 +4,12 @@ This folder contains evaluation harness for evaluating agents on the Entity-dedu
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
|
||||
## Start the evaluation
|
||||
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-XXX"; # This is required for evaluation (to simulate another party of conversation)
|
||||
./evaluation/benchmarks/EDA/scripts/run_infer.sh [model_config] [git-version] [agent] [dataset] [eval_limit]
|
||||
@@ -35,8 +37,7 @@ For example,
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```bibtex
|
||||
```
|
||||
@inproceedings{zhang2023entity,
|
||||
title={Probing the Multi-turn Planning Capabilities of LLMs via 20 Question Games},
|
||||
author={Zhang, Yizhe and Lu, Jiarui and Jaitly, Navdeep},
|
||||
|
||||
@@ -21,7 +21,7 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
if [ -z "$DATASET" ]; then
|
||||
echo "Dataset not specified, use default 'things'"
|
||||
@@ -34,9 +34,12 @@ if [ -z "$OPENAI_API_KEY" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# IMPORTANT: Because Agent's prompt changes fairly often in the rapidly evolving codebase of OpenHands
|
||||
# We need to track the version of Agent in the evaluation to make sure results are comparable
|
||||
AGENT_VERSION=v$(poetry run python -c "import openhands.agenthub; from openhands.controller.agent import Agent; print(Agent.get_cls('$AGENT').VERSION)")
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
echo "DATASET: $DATASET"
|
||||
|
||||
@@ -48,7 +51,7 @@ COMMAND="poetry run python evaluation/benchmarks/EDA/run_infer.py \
|
||||
--max-iterations 20 \
|
||||
--OPENAI_API_KEY $OPENAI_API_KEY \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note ${OPENHANDS_VERSION}_${DATASET}"
|
||||
--eval-note ${AGENT_VERSION}_${DATASET}"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -4,7 +4,7 @@ This folder contains evaluation harness for evaluating agents on the [AgentBench
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Start the evaluation
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
COMMAND="export PYTHONPATH=evaluation/benchmarks/agent_bench:\$PYTHONPATH && poetry run python evaluation/benchmarks/agent_bench/run_infer.py \
|
||||
@@ -31,7 +31,7 @@ COMMAND="export PYTHONPATH=evaluation/benchmarks/agent_bench:\$PYTHONPATH && poe
|
||||
--llm-config $MODEL_CONFIG \
|
||||
--max-iterations 30 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note $OPENHANDS_VERSION"
|
||||
--eval-note $AGENT_VERSION"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -10,7 +10,7 @@ Hugging Face dataset based on the
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local
|
||||
Please follow instruction [here](../README.md#setup) to setup your local
|
||||
development environment and LLM.
|
||||
|
||||
## Start the evaluation
|
||||
|
||||
@@ -21,13 +21,13 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
EVAL_NOTE=$OPENHANDS_VERSION
|
||||
EVAL_NOTE=$AGENT_VERSION
|
||||
|
||||
# Default to NOT use unit tests.
|
||||
if [ -z "$USE_UNIT_TESTS" ]; then
|
||||
|
||||
@@ -4,14 +4,13 @@ Implements evaluation of agents on BioCoder from the BioCoder benchmark introduc
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## BioCoder Docker Image
|
||||
|
||||
In the openhands branch of the Biocoder repository, we have slightly modified our original Docker image to work with the OpenHands environment. In the Docker image are testing scripts (`/testing/start_test_openhands.py` and aux files in `/testing_files/`) to assist with evaluation. Additionally, we have installed all dependencies, including OpenJDK, mamba (with Python 3.6), and many system libraries. Notably, we have **not** packaged all repositories into the image, so they are downloaded at runtime.
|
||||
|
||||
**Before first execution, pull our Docker image with the following command**
|
||||
|
||||
```bash
|
||||
docker pull public.ecr.aws/i5g0m1f6/eval_biocoder:v1.0
|
||||
```
|
||||
@@ -20,6 +19,7 @@ To reproduce this image, please see the Dockerfile_Openopenhands in the `biocode
|
||||
|
||||
## Start the evaluation
|
||||
|
||||
|
||||
```bash
|
||||
./evaluation/benchmarks/biocoder/scripts/run_infer.sh [model_config] [git-version] [agent] [eval_limit]
|
||||
```
|
||||
@@ -47,8 +47,7 @@ with current OpenHands version, then your command would be:
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```bibtex
|
||||
```
|
||||
@misc{tang2024biocoder,
|
||||
title={BioCoder: A Benchmark for Bioinformatics Code Generation with Large Language Models},
|
||||
author={Xiangru Tang and Bill Qian and Rick Gao and Jiakang Chen and Xinyun Chen and Mark Gerstein},
|
||||
|
||||
@@ -21,10 +21,10 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
echo "DATASET: $DATASET"
|
||||
|
||||
@@ -33,7 +33,7 @@ COMMAND="poetry run python evaluation/benchmarks/biocoder/run_infer.py \
|
||||
--llm-config $MODEL_CONFIG \
|
||||
--max-iterations 10 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note ${OPENHANDS_VERSION}_${DATASET}"
|
||||
--eval-note ${AGENT_VERSION}_${DATASET}"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -20,10 +20,10 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/bird/run_infer.py \
|
||||
@@ -31,7 +31,7 @@ COMMAND="poetry run python evaluation/benchmarks/bird/run_infer.py \
|
||||
--llm-config $MODEL_CONFIG \
|
||||
--max-iterations 5 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note $OPENHANDS_VERSION" \
|
||||
--eval-note $AGENT_VERSION" \
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -7,7 +7,7 @@ If so, the browsing performance upper-bound of CodeActAgent will be the performa
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Run Inference
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
EVAL_NOTE="$OPENHANDS_VERSION"
|
||||
EVAL_NOTE="$AGENT_VERSION"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/browsing_delegation/run_infer.py \
|
||||
--agent-cls $AGENT \
|
||||
|
||||
@@ -4,18 +4,19 @@ This folder contains the evaluation harness that we built on top of the original
|
||||
|
||||
The evaluation consists of three steps:
|
||||
|
||||
1. Environment setup: [install python environment](../../README.md#development-environment), [configure LLM config](../../README.md#configure-openhands-and-your-llm).
|
||||
1. Environment setup: [install python environment](../README.md#development-environment), [configure LLM config](../README.md#configure-openhands-and-your-llm).
|
||||
2. [Run Evaluation](#run-inference-on-commit0-instances): Generate a edit patch for each Commit0 Repo, and get the evaluation results
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## OpenHands Commit0 Instance-level Docker Support
|
||||
|
||||
OpenHands supports using the Commit0 Docker for **[inference](#run-inference-on-commit0-instances).
|
||||
This is now the default behavior.
|
||||
|
||||
|
||||
## Run Inference on Commit0 Instances
|
||||
|
||||
Make sure your Docker daemon is running, and you have ample disk space (at least 200-500GB, depends on the Commit0 set you are running on) for the [instance-level docker image](#openhands-commit0-instance-level-docker-support).
|
||||
|
||||
@@ -61,10 +61,10 @@ echo "USE_INSTANCE_IMAGE: $USE_INSTANCE_IMAGE"
|
||||
export RUN_WITH_BROWSING=$RUN_WITH_BROWSING
|
||||
echo "RUN_WITH_BROWSING: $RUN_WITH_BROWSING"
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
echo "DATASET: $DATASET"
|
||||
echo "HF SPLIT: $SPLIT"
|
||||
@@ -75,7 +75,7 @@ if [ -z "$USE_HINT_TEXT" ]; then
|
||||
export USE_HINT_TEXT=false
|
||||
fi
|
||||
echo "USE_HINT_TEXT: $USE_HINT_TEXT"
|
||||
EVAL_NOTE="$OPENHANDS_VERSION"
|
||||
EVAL_NOTE="$AGENT_VERSION"
|
||||
# if not using Hint, add -no-hint to the eval note
|
||||
if [ "$USE_HINT_TEXT" = false ]; then
|
||||
EVAL_NOTE="$EVAL_NOTE-no-hint"
|
||||
|
||||
@@ -23,10 +23,10 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/discoverybench/run_infer.py \
|
||||
@@ -35,7 +35,7 @@ COMMAND="poetry run python evaluation/benchmarks/discoverybench/run_infer.py \
|
||||
--max-iterations 10 \
|
||||
--max-chars 10000000 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note $OPENHANDS_VERSION"
|
||||
--eval-note $AGENT_VERSION"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -4,10 +4,9 @@ This folder contains evaluation harness for evaluating agents on the [GAIA bench
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Run the evaluation
|
||||
|
||||
We are using the GAIA dataset hosted on [Hugging Face](https://huggingface.co/datasets/gaia-benchmark/GAIA).
|
||||
Please accept the terms and make sure to have logged in on your computer by `huggingface-cli login` before running the evaluation.
|
||||
|
||||
@@ -42,7 +41,6 @@ For example,
|
||||
## Get score
|
||||
|
||||
Then you can get stats by running the following command:
|
||||
|
||||
```bash
|
||||
python ./evaluation/benchmarks/gaia/get_score.py \
|
||||
--file <path_to/output.json>
|
||||
|
||||
@@ -21,17 +21,17 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
if [ -z "$LEVELS" ]; then
|
||||
LEVELS="2023_level1"
|
||||
echo "Levels not specified, use default $LEVELS"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
echo "LEVELS: $LEVELS"
|
||||
|
||||
@@ -42,7 +42,7 @@ COMMAND="poetry run python ./evaluation/benchmarks/gaia/run_infer.py \
|
||||
--level $LEVELS \
|
||||
--data-split validation \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note ${OPENHANDS_VERSION}_${LEVELS}"
|
||||
--eval-note ${AGENT_VERSION}_${LEVELS}"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -4,7 +4,7 @@ This folder contains evaluation harness we built on top of the original [Gorilla
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Run Inference on APIBench Instances
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
if [ -z "$HUBS" ]; then
|
||||
HUBS="hf,torch,tf"
|
||||
@@ -29,7 +29,7 @@ if [ -z "$HUBS" ]; then
|
||||
fi
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
echo "HUBS: $HUBS"
|
||||
|
||||
@@ -40,7 +40,7 @@ COMMAND="poetry run python evaluation/benchmarks/gorilla/run_infer.py \
|
||||
--hubs $HUBS \
|
||||
--data-split validation \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note ${OPENHANDS_VERSION}_${LEVELS}"
|
||||
--eval-note ${AGENT_VERSION}_${LEVELS}"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
Implements the evaluation of agents on the GPQA benchmark introduced in [GPQA: A Graduate-Level Google-Proof Q&A Benchmark](https://arxiv.org/abs/2308.07124).
|
||||
|
||||
This code implements the evaluation of agents on the GPQA Benchmark with Open Book setting.
|
||||
|
||||
- The benchmark consists of 448 high-quality and extremely difficult multiple-choice questions in the domains of biology, physics, and chemistry. The questions are intentionally designed to be "Google-proof," meaning that even highly skilled non-expert validators achieve only 34% accuracy despite unrestricted access to the web.
|
||||
- Even experts in the corresponding domains achieve only 65% accuracy.
|
||||
- State-of-the-art AI systems achieve only 39% accuracy on this challenging dataset.
|
||||
@@ -12,24 +11,20 @@ This code implements the evaluation of agents on the GPQA Benchmark with Open Bo
|
||||
Accurate solving of above graduate level questions would require both tool use (e.g., python for calculations) and web-search for finding related facts as information required for the questions might not be part of the LLM knowledge / training data.
|
||||
|
||||
Further references:
|
||||
|
||||
- <https://arxiv.org/pdf/2311.12022>
|
||||
- <https://paperswithcode.com/dataset/gpqa>
|
||||
- <https://github.com/idavidrein/gpqa>
|
||||
- https://arxiv.org/pdf/2311.12022
|
||||
- https://paperswithcode.com/dataset/gpqa
|
||||
- https://github.com/idavidrein/gpqa
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Run Inference on GPQA Benchmark
|
||||
|
||||
'gpqa_main', 'gqpa_diamond', 'gpqa_experts', 'gpqa_extended' -- data split options
|
||||
From the root of the OpenHands repo, run the following command:
|
||||
|
||||
```bash
|
||||
./evaluation/benchmarks/gpqa/scripts/run_infer.sh [model_config_name] [git-version] [num_samples_eval] [data_split] [AgentClass]
|
||||
```
|
||||
|
||||
You can replace `model_config_name` with any model you set up in `config.toml`.
|
||||
|
||||
- `model_config_name`: The model configuration name from `config.toml` that you want to evaluate.
|
||||
|
||||
@@ -27,10 +27,10 @@ if [ -z "$DATA_SPLIT" ]; then
|
||||
DATA_SPLIT="gpqa_diamond"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/gpqa/run_infer.py \
|
||||
@@ -39,7 +39,7 @@ COMMAND="poetry run python evaluation/benchmarks/gpqa/run_infer.py \
|
||||
--max-iterations 10 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--data-split $DATA_SPLIT \
|
||||
--eval-note $OPENHANDS_VERSION"
|
||||
--eval-note $AGENT_VERSION"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -4,7 +4,7 @@ Implements evaluation of agents on HumanEvalFix from the HumanEvalPack benchmark
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Run Inference on HumanEvalFix
|
||||
|
||||
@@ -14,11 +14,13 @@ Please follow instruction [here](../../README.md#setup) to setup your local deve
|
||||
|
||||
You can replace `eval_gpt4_1106_preview` with any model you set up in `config.toml`.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
For each problem, OpenHands is given a set number of iterations to fix the failing code. The history field shows each iteration's response to correct its code that fails any test case.
|
||||
|
||||
```json
|
||||
|
||||
```
|
||||
{
|
||||
"task_id": "Python/2",
|
||||
"instruction": "Please fix the function in Python__2.py such that all test cases pass.\nEnvironment has been set up for you to start working. You may assume all necessary tools are installed.\n\n# Problem Statement\ndef truncate_number(number: float) -> float:\n return number % 1.0 + 1.0\n\n\n\n\n\n\ndef check(truncate_number):\n assert truncate_number(3.5) == 0.5\n assert abs(truncate_number(1.33) - 0.33) < 1e-6\n assert abs(truncate_number(123.456) - 0.456) < 1e-6\n\ncheck(truncate_number)\n\nIMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.\nYou should NOT modify any existing test case files. If needed, you can add new test cases in a NEW file to reproduce the issue.\nYou SHOULD INCLUDE PROPER INDENTATION in your edit commands.\nWhen you think you have fixed the issue through code changes, please finish the interaction using the "finish" tool.\n",
|
||||
|
||||
@@ -58,10 +58,10 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/humanevalfix/run_infer.py \
|
||||
@@ -69,7 +69,7 @@ COMMAND="poetry run python evaluation/benchmarks/humanevalfix/run_infer.py \
|
||||
--llm-config $MODEL_CONFIG \
|
||||
--max-iterations 10 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note $OPENHANDS_VERSION"
|
||||
--eval-note $AGENT_VERSION"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -4,10 +4,9 @@ This folder contains evaluation harness for evaluating agents on the logic reaso
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Run Inference on logic_reasoning
|
||||
|
||||
The following code will run inference on the first example of the ProofWriter dataset,
|
||||
|
||||
```bash
|
||||
|
||||
@@ -28,10 +28,10 @@ if [ -z "$DATASET" ]; then
|
||||
DATASET="ProofWriter"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/logic_reasoning/run_infer.py \
|
||||
@@ -40,7 +40,7 @@ COMMAND="poetry run python evaluation/benchmarks/logic_reasoning/run_infer.py \
|
||||
--dataset $DATASET \
|
||||
--max-iterations 10 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note $OPENHANDS_VERSION"
|
||||
--eval-note $AGENT_VERSION"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -4,7 +4,7 @@ This folder contains evaluation for [MiniWoB++](https://miniwob.farama.org/) ben
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Test if your environment works
|
||||
|
||||
@@ -42,6 +42,7 @@ poetry run python evaluation/benchmarks/miniwob/get_success_rate.py evaluation/e
|
||||
|
||||
You can start your own fork of [our huggingface evaluation outputs](https://huggingface.co/spaces/OpenHands/evaluation) and submit a PR of your evaluation results following the guide [here](https://huggingface.co/docs/hub/en/repositories-pull-requests-discussions#pull-requests-and-discussions).
|
||||
|
||||
|
||||
## BrowsingAgent V1.0 result
|
||||
|
||||
Tested on BrowsingAgent V1.0
|
||||
|
||||
@@ -25,13 +25,13 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="BrowsingAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
EVAL_NOTE="${OPENHANDS_VERSION}_${NOTE}"
|
||||
EVAL_NOTE="${AGENT_VERSION}_${NOTE}"
|
||||
|
||||
COMMAND="export PYTHONPATH=evaluation/benchmarks/miniwob:\$PYTHONPATH && poetry run python evaluation/benchmarks/miniwob/run_infer.py \
|
||||
--agent-cls $AGENT \
|
||||
|
||||
@@ -18,10 +18,10 @@ checkout_eval_branch
|
||||
# Only 'CodeActAgent' is supported for MINT now
|
||||
AGENT="CodeActAgent"
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
|
||||
export PYTHONPATH=$(pwd)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ For more details on the ML-Bench task and dataset, please refer to the paper: [M
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Run Inference on ML-Bench
|
||||
|
||||
|
||||
@@ -26,10 +26,10 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/ml_bench/run_infer.py \
|
||||
@@ -37,7 +37,7 @@ COMMAND="poetry run python evaluation/benchmarks/ml_bench/run_infer.py \
|
||||
--llm-config $MODEL_CONFIG \
|
||||
--max-iterations 10 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note $OPENHANDS_VERSION"
|
||||
--eval-note $AGENT_VERSION"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# ScienceAgentBench Evaluation with OpenHands
|
||||
|
||||
This folder contains the evaluation harness for [ScienceAgentBench](https://osu-nlp-group.github.io/ScienceAgentBench/) (paper: <https://arxiv.org/abs/2410.05080>).
|
||||
This folder contains the evaluation harness for [ScienceAgentBench](https://osu-nlp-group.github.io/ScienceAgentBench/) (paper: https://arxiv.org/abs/2410.05080).
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Setup ScienceAgentBench
|
||||
|
||||
@@ -45,7 +45,6 @@ After the inference is completed, you may use the following command to extract n
|
||||
```bash
|
||||
python post_proc.py [log_fname]
|
||||
```
|
||||
|
||||
- `log_fname`, e.g. `evaluation/.../output.jsonl`, is the automatically saved trajectory log of an OpenHands agent.
|
||||
|
||||
Output will be write to e.g. `evaluation/.../output.converted.jsonl`
|
||||
|
||||
@@ -26,10 +26,10 @@ if [ -z "$USE_KNOWLEDGE" ]; then
|
||||
USE_KNOWLEDGE=false
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/scienceagentbench/run_infer.py \
|
||||
@@ -38,7 +38,7 @@ COMMAND="poetry run python evaluation/benchmarks/scienceagentbench/run_infer.py
|
||||
--use_knowledge $USE_KNOWLEDGE \
|
||||
--max-iterations 30 \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note $OPENHANDS_VERSION" \
|
||||
--eval-note $AGENT_VERSION" \
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -6,19 +6,20 @@ This folder contains the evaluation harness that we built on top of the original
|
||||
|
||||
The evaluation consists of three steps:
|
||||
|
||||
1. Environment setup: [install python environment](../../README.md#development-environment), [configure LLM config](../../README.md#configure-openhands-and-your-llm), and [pull docker](#openhands-swe-bench-instance-level-docker-support).
|
||||
1. Environment setup: [install python environment](../README.md#development-environment), [configure LLM config](../README.md#configure-openhands-and-your-llm), and [pull docker](#openhands-swe-bench-instance-level-docker-support).
|
||||
2. [Run inference](#run-inference-on-swe-bench-instances): Generate a edit patch for each Github issue
|
||||
3. [Evaluate patches using SWE-Bench docker](#evaluate-generated-patches)
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## OpenHands SWE-Bench Instance-level Docker Support
|
||||
|
||||
OpenHands now support using the [official evaluation docker](https://github.com/princeton-nlp/SWE-bench/blob/main/docs/20240627_docker/README.md) for both **[inference](#run-inference-on-swe-bench-instances) and [evaluation](#evaluate-generated-patches)**.
|
||||
This is now the default behavior.
|
||||
|
||||
|
||||
## Run Inference on SWE-Bench Instances
|
||||
|
||||
Make sure your Docker daemon is running, and you have ample disk space (at least 200-500GB, depends on the SWE-Bench set you are running on) for the [instance-level docker image](#openhands-swe-bench-instance-level-docker-support).
|
||||
@@ -51,8 +52,7 @@ default, it is set to 1.
|
||||
- `dataset_split`, split for the huggingface dataset. e.g., `test`, `dev`. Default to `test`.
|
||||
|
||||
There are also two optional environment variables you can set.
|
||||
|
||||
```bash
|
||||
```
|
||||
export USE_HINT_TEXT=true # if you want to use hint text in the evaluation. Default to false. Ignore this if you are not sure.
|
||||
export USE_INSTANCE_IMAGE=true # if you want to use instance-level docker images. Default to true
|
||||
```
|
||||
@@ -127,7 +127,6 @@ With `output.jsonl` file, you can run `eval_infer.sh` to evaluate generated patc
|
||||
**This evaluation is performed using the official dockerized evaluation announced [here](https://github.com/princeton-nlp/SWE-bench/blob/main/docs/20240627_docker/README.md).**
|
||||
|
||||
> If you want to evaluate existing results, you should first run this to clone existing outputs
|
||||
>
|
||||
>```bash
|
||||
>git clone https://huggingface.co/spaces/OpenHands/evaluation evaluation/evaluation_outputs
|
||||
>```
|
||||
@@ -144,7 +143,6 @@ Then you can run the following:
|
||||
```
|
||||
|
||||
The script now accepts optional arguments:
|
||||
|
||||
- `instance_id`: Specify a single instance to evaluate (optional)
|
||||
- `dataset_name`: The name of the dataset to use (default: `"princeton-nlp/SWE-bench_Lite"`)
|
||||
- `split`: The split of the dataset to use (default: `"test"`)
|
||||
@@ -181,6 +179,7 @@ To clean-up all existing runtimes that you've already started, run:
|
||||
ALLHANDS_API_KEY="YOUR-API-KEY" ./evaluation/benchmarks/swe_bench/scripts/cleanup_remote_runtime.sh
|
||||
```
|
||||
|
||||
|
||||
## Visualize Results
|
||||
|
||||
First you need to clone `https://huggingface.co/spaces/OpenHands/evaluation` and add your own running results from openhands into the `outputs` of the cloned repo.
|
||||
@@ -190,7 +189,6 @@ git clone https://huggingface.co/spaces/OpenHands/evaluation
|
||||
```
|
||||
|
||||
**(optional) setup streamlit environment with conda**:
|
||||
|
||||
```bash
|
||||
cd evaluation
|
||||
conda create -n streamlit python=3.10
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
from collections import Counter
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from openhands.events.serialization import event_from_dict
|
||||
from openhands.events.utils import get_pairs_from_events
|
||||
|
||||
@@ -14,21 +10,25 @@ ERROR_KEYWORDS = [
|
||||
'Agent encountered an error while processing the last action',
|
||||
'APIError',
|
||||
'Action execution failed',
|
||||
'litellm.Timeout: APITimeoutError',
|
||||
]
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('output_file', type=str, help='The file to summarize')
|
||||
args = parser.parse_args()
|
||||
|
||||
def process_file(file_path):
|
||||
with open(file_path, 'r') as file:
|
||||
with open(args.output_file, 'r') as file:
|
||||
lines = file.readlines()
|
||||
|
||||
num_lines = len(lines)
|
||||
num_error_lines = 0
|
||||
num_agent_stuck_in_loop = 0
|
||||
|
||||
num_resolved = 0
|
||||
num_empty_patch = 0
|
||||
num_unfinished_runs = 0
|
||||
|
||||
error_counter = Counter()
|
||||
|
||||
main_agent_cost = []
|
||||
editor_cost = []
|
||||
num_turns = []
|
||||
@@ -36,11 +36,6 @@ def process_file(file_path):
|
||||
for line in lines:
|
||||
_d = json.loads(line)
|
||||
|
||||
if 'metrics' not in _d or _d['metrics'] is None:
|
||||
# this is a failed run
|
||||
num_unfinished_runs += 1
|
||||
continue
|
||||
|
||||
# Cost
|
||||
costs = _d['metrics'].get('costs', [])
|
||||
_cur_main_agent_cost = 0
|
||||
@@ -94,186 +89,30 @@ def process_file(file_path):
|
||||
num_error_lines += 1
|
||||
break
|
||||
|
||||
return {
|
||||
'file_path': file_path,
|
||||
'total_instances': num_lines,
|
||||
'resolved': {
|
||||
'count': num_resolved,
|
||||
'percentage': (num_resolved / num_lines * 100) if num_lines > 0 else 0,
|
||||
},
|
||||
'empty_patches': {
|
||||
'count': num_empty_patch,
|
||||
'percentage': (num_empty_patch / num_lines * 100) if num_lines > 0 else 0,
|
||||
},
|
||||
'unfinished_runs': {
|
||||
'count': num_unfinished_runs,
|
||||
'percentage': (num_unfinished_runs / num_lines * 100)
|
||||
if num_lines > 0
|
||||
else 0,
|
||||
},
|
||||
'errors': {
|
||||
'total': num_error_lines,
|
||||
'percentage': (num_error_lines / num_lines * 100) if num_lines > 0 else 0,
|
||||
'stuck_in_loop': {
|
||||
'count': num_agent_stuck_in_loop,
|
||||
'percentage': (num_agent_stuck_in_loop / num_lines * 100)
|
||||
if num_lines > 0
|
||||
else 0,
|
||||
},
|
||||
'breakdown': {
|
||||
str(error): {
|
||||
'count': count,
|
||||
'percentage': (count / num_lines * 100) if num_lines > 0 else 0,
|
||||
}
|
||||
for error, count in error_counter.items()
|
||||
},
|
||||
},
|
||||
'costs': {
|
||||
'main_agent': sum(main_agent_cost),
|
||||
'editor': sum(editor_cost),
|
||||
'total': sum(main_agent_cost) + sum(editor_cost),
|
||||
},
|
||||
'statistics': {
|
||||
'avg_turns': sum(num_turns) / num_lines if num_lines > 0 else 0,
|
||||
'costs': {
|
||||
'main_agent': sum(main_agent_cost) / num_lines if num_lines > 0 else 0,
|
||||
'editor': sum(editor_cost) / num_lines if num_lines > 0 else 0,
|
||||
'total': (sum(main_agent_cost) + sum(editor_cost)) / num_lines
|
||||
if num_lines > 0
|
||||
else 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def aggregate_directory(input_path) -> pd.DataFrame:
|
||||
# Process all output.jsonl files in subdirectories
|
||||
pattern = os.path.join(input_path, '**/output.jsonl')
|
||||
files = glob.glob(pattern, recursive=True)
|
||||
print(f'Processing {len(files)} files from directory {input_path}')
|
||||
|
||||
# Process each file silently and collect results
|
||||
results = []
|
||||
for file_path in files:
|
||||
try:
|
||||
result = process_file(file_path)
|
||||
results.append(result)
|
||||
except Exception as e:
|
||||
print(f'Error processing {file_path}: {str(e)}')
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
continue
|
||||
|
||||
# Convert results to pandas DataFrame and sort by resolve rate
|
||||
df = pd.DataFrame(results)
|
||||
|
||||
# Extract directory name from file path
|
||||
df['directory'] = df['file_path'].apply(
|
||||
lambda x: os.path.basename(os.path.dirname(x))
|
||||
# print the error counter (with percentage)
|
||||
print(
|
||||
f'Number of resolved: {num_resolved} / {num_lines} ({num_resolved / num_lines * 100:.2f}%)'
|
||||
)
|
||||
print(
|
||||
f'Number of empty patch: {num_empty_patch} / {num_lines} ({num_empty_patch / num_lines * 100:.2f}%)'
|
||||
)
|
||||
print(
|
||||
f'Number of error lines: {num_error_lines} / {num_lines} ({num_error_lines / num_lines * 100:.2f}%)'
|
||||
)
|
||||
print(
|
||||
f'Number of agent stuck in loop: {num_agent_stuck_in_loop} / {num_lines} ({num_agent_stuck_in_loop / num_lines * 100:.2f}%)'
|
||||
)
|
||||
assert len(num_turns) == num_lines
|
||||
assert len(main_agent_cost) == num_lines
|
||||
assert len(editor_cost) == num_lines
|
||||
print('## Statistics')
|
||||
print(f'Avg. num of turns per instance: {sum(num_turns) / num_lines:.2f}')
|
||||
print(f'Avg. agent cost per instance: {sum(main_agent_cost) / num_lines:.2f} USD')
|
||||
print(f'Avg. editor cost per instance: {sum(editor_cost) / num_lines:.2f} USD')
|
||||
print(
|
||||
f'Avg. total cost per instance: {(sum(main_agent_cost) + sum(editor_cost)) / num_lines:.2f} USD'
|
||||
)
|
||||
|
||||
df['resolve_rate'] = df['resolved'].apply(lambda x: x['percentage'])
|
||||
df['empty_patch_rate'] = df['empty_patches'].apply(lambda x: x['percentage'])
|
||||
df['unfinished_rate'] = df['unfinished_runs'].apply(lambda x: x['percentage'])
|
||||
df['avg_turns'] = df['statistics'].apply(lambda x: x['avg_turns'])
|
||||
df['error_rate'] = df['errors'].apply(lambda x: x['percentage'])
|
||||
df['avg_cost'] = df['statistics'].apply(lambda x: x['costs']['total'])
|
||||
|
||||
df = df.sort_values('resolve_rate', ascending=False)
|
||||
|
||||
return df
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'input_path', type=str, help='The file or directory to summarize'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--output',
|
||||
type=str,
|
||||
help='Output JSONL file for results',
|
||||
default='summary_results.jsonl',
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if os.path.isdir(args.input_path):
|
||||
df = aggregate_directory(args.input_path)
|
||||
# Create the summary string
|
||||
columns = [
|
||||
'directory',
|
||||
'resolve_rate',
|
||||
'empty_patch_rate',
|
||||
'unfinished_rate',
|
||||
'error_rate',
|
||||
'avg_turns',
|
||||
'avg_cost',
|
||||
'total_instances',
|
||||
]
|
||||
summary_str = df[columns].to_string(
|
||||
float_format=lambda x: '{:.2f}'.format(x),
|
||||
formatters={
|
||||
'directory': lambda x: x[:90]
|
||||
}, # Truncate directory names to 20 chars
|
||||
index=False,
|
||||
)
|
||||
|
||||
# Print to console
|
||||
print('\nResults summary (sorted by resolve rate):')
|
||||
print(summary_str)
|
||||
|
||||
# Save to text file
|
||||
txt_output = args.output.rsplit('.', 1)[0] + '.txt'
|
||||
with open(txt_output, 'w') as f:
|
||||
f.write('Results summary (sorted by resolve rate):\n')
|
||||
f.write(summary_str)
|
||||
|
||||
# Save
|
||||
df.to_json(args.output, lines=True, orient='records')
|
||||
df[columns].to_csv(args.output.rsplit('.', 1)[0] + '.csv', index=False)
|
||||
else:
|
||||
# Process single file with detailed output
|
||||
results = []
|
||||
try:
|
||||
result = process_file(args.input_path)
|
||||
results.append(result)
|
||||
|
||||
# Print detailed results for single file
|
||||
print(f'\nResults for {args.input_path}:')
|
||||
print(
|
||||
f"Number of resolved: {result['resolved']['count']} / {result['total_instances']} ({result['resolved']['percentage']:.2f}%)"
|
||||
)
|
||||
print(
|
||||
f"Number of empty patch: {result['empty_patches']['count']} / {result['total_instances']} ({result['empty_patches']['percentage']:.2f}%)"
|
||||
)
|
||||
print(
|
||||
f"Number of error lines: {result['errors']['total']} / {result['total_instances']} ({result['errors']['percentage']:.2f}%)"
|
||||
)
|
||||
print(
|
||||
f"Number of agent stuck in loop: {result['errors']['stuck_in_loop']['count']} / {result['total_instances']} ({result['errors']['stuck_in_loop']['percentage']:.2f}%)"
|
||||
)
|
||||
print(
|
||||
f"Number of unfinished runs: {result['unfinished_runs']['count']} / {result['total_instances']} ({result['unfinished_runs']['percentage']:.2f}%)"
|
||||
)
|
||||
print(f"Total cost: {result['costs']['total']:.2f} USD")
|
||||
print('## Statistics')
|
||||
print(
|
||||
f"Avg. num of turns per instance: {result['statistics']['avg_turns']:.2f}"
|
||||
)
|
||||
print(
|
||||
f"Avg. agent cost per instance: {result['statistics']['costs']['main_agent']:.2f} USD"
|
||||
)
|
||||
print(
|
||||
f"Avg. editor cost per instance: {result['statistics']['costs']['editor']:.2f} USD"
|
||||
)
|
||||
print(
|
||||
f"Avg. total cost per instance: {result['statistics']['costs']['total']:.2f} USD"
|
||||
)
|
||||
|
||||
print('## Detailed error breakdown:')
|
||||
for error, data in result['errors']['breakdown'].items():
|
||||
print(f"{error}: {data['count']} ({data['percentage']:.2f}%)")
|
||||
|
||||
except Exception as e:
|
||||
print(f'Error processing {args.input_path}: {str(e)}')
|
||||
print('## Detailed error breakdown:')
|
||||
for error, count in error_counter.items():
|
||||
print(f'{error}: {count} ({count / num_lines * 100:.2f}%)')
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
import argparse
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from openhands.core.logger import openhands_logger as logger
|
||||
|
||||
|
||||
def verify_instance_costs(row: pd.Series) -> float:
|
||||
"""
|
||||
Verifies that the accumulated_cost matches the sum of individual costs in metrics.
|
||||
Also checks for duplicate consecutive costs which might indicate buggy counting.
|
||||
If the consecutive costs are identical, the file is affected by this bug:
|
||||
https://github.com/All-Hands-AI/OpenHands/issues/5383
|
||||
|
||||
Args:
|
||||
row: DataFrame row containing instance data with metrics
|
||||
Returns:
|
||||
float: The verified total cost for this instance (corrected if needed)
|
||||
"""
|
||||
try:
|
||||
metrics = row.get('metrics')
|
||||
if not metrics:
|
||||
logger.warning(f"Instance {row['instance_id']}: No metrics found")
|
||||
return 0.0
|
||||
|
||||
accumulated = metrics.get('accumulated_cost')
|
||||
costs = metrics.get('costs', [])
|
||||
|
||||
if accumulated is None:
|
||||
logger.warning(
|
||||
f"Instance {row['instance_id']}: No accumulated_cost in metrics"
|
||||
)
|
||||
return 0.0
|
||||
|
||||
# Check for duplicate consecutive costs and systematic even-odd pairs
|
||||
has_duplicate = False
|
||||
all_pairs_match = True
|
||||
|
||||
# Check each even-odd pair (0-1, 2-3, etc.)
|
||||
for i in range(0, len(costs) - 1, 2):
|
||||
if abs(costs[i]['cost'] - costs[i + 1]['cost']) < 1e-6:
|
||||
has_duplicate = True
|
||||
logger.debug(
|
||||
f"Instance {row['instance_id']}: Possible buggy double-counting detected! "
|
||||
f"Steps {i} and {i+1} have identical costs: {costs[i]['cost']:.2f}"
|
||||
)
|
||||
else:
|
||||
all_pairs_match = False
|
||||
break
|
||||
|
||||
# Calculate total cost, accounting for buggy double counting if detected
|
||||
if len(costs) >= 2 and has_duplicate and all_pairs_match:
|
||||
paired_steps_cost = sum(
|
||||
cost_entry['cost']
|
||||
for cost_entry in costs[: -1 if len(costs) % 2 else None]
|
||||
)
|
||||
real_paired_cost = paired_steps_cost / 2
|
||||
|
||||
unpaired_cost = costs[-1]['cost'] if len(costs) % 2 else 0
|
||||
total_cost = real_paired_cost + unpaired_cost
|
||||
|
||||
else:
|
||||
total_cost = sum(cost_entry['cost'] for cost_entry in costs)
|
||||
|
||||
if not abs(total_cost - accumulated) < 1e-6:
|
||||
logger.warning(
|
||||
f"Instance {row['instance_id']}: Cost mismatch: "
|
||||
f"accumulated: {accumulated:.2f}, sum of costs: {total_cost:.2f}, "
|
||||
)
|
||||
|
||||
return total_cost
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Error verifying costs for instance {row.get('instance_id', 'UNKNOWN')}: {e}"
|
||||
)
|
||||
return 0.0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Verify costs in SWE-bench output file'
|
||||
)
|
||||
parser.add_argument(
|
||||
'input_filepath', type=str, help='Path to the output.jsonl file'
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
# Load and verify the JSONL file
|
||||
df = pd.read_json(args.input_filepath, lines=True)
|
||||
logger.info(f'Loaded {len(df)} instances from {args.input_filepath}')
|
||||
|
||||
# Verify costs for each instance and sum up total
|
||||
total_cost = df.apply(verify_instance_costs, axis=1).sum()
|
||||
logger.info(f'Total verified cost across all instances: ${total_cost:.2f}')
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to process file: {e}')
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -55,10 +55,10 @@ echo "USE_INSTANCE_IMAGE: $USE_INSTANCE_IMAGE"
|
||||
export RUN_WITH_BROWSING=$RUN_WITH_BROWSING
|
||||
echo "RUN_WITH_BROWSING: $RUN_WITH_BROWSING"
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
echo "DATASET: $DATASET"
|
||||
echo "SPLIT: $SPLIT"
|
||||
@@ -68,7 +68,7 @@ if [ -z "$USE_HINT_TEXT" ]; then
|
||||
export USE_HINT_TEXT=false
|
||||
fi
|
||||
echo "USE_HINT_TEXT: $USE_HINT_TEXT"
|
||||
EVAL_NOTE="$OPENHANDS_VERSION"
|
||||
EVAL_NOTE="$AGENT_VERSION"
|
||||
# if not using Hint, add -no-hint to the eval note
|
||||
if [ "$USE_HINT_TEXT" = false ]; then
|
||||
EVAL_NOTE="$EVAL_NOTE-no-hint"
|
||||
|
||||
@@ -33,7 +33,7 @@ if [ -d /workspace/$WORKSPACE_NAME ]; then
|
||||
rm -rf /workspace/$WORKSPACE_NAME
|
||||
fi
|
||||
mkdir -p /workspace
|
||||
mv /testbed /workspace/$WORKSPACE_NAME
|
||||
ln -s /testbed /workspace/$WORKSPACE_NAME
|
||||
|
||||
# Activate instance-specific environment
|
||||
. /opt/miniconda3/etc/profile.d/conda.sh
|
||||
|
||||
@@ -4,7 +4,7 @@ This folder contains an evaluation harness we built on top of the original [Tool
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Run Inference on ToolQA Instances
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ if [ -z "$WOLFRAM_APPID" ]; then
|
||||
echo "WOLFRAM_APPID not specified"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
echo "DATASET: $DATASET"
|
||||
echo "HARDNESS: $HARDNESS"
|
||||
@@ -56,7 +56,7 @@ COMMAND="poetry run python evaluation/benchmarks/toolqa/run_infer.py \
|
||||
--wolfram_alpha_appid $WOLFRAM_APPID\
|
||||
--data-split validation \
|
||||
--eval-num-workers $NUM_WORKERS \
|
||||
--eval-note ${OPENHANDS_VERSION}_${LEVELS}"
|
||||
--eval-note ${AGENT_VERSION}_${LEVELS}"
|
||||
|
||||
if [ -n "$EVAL_LIMIT" ]; then
|
||||
echo "EVAL_LIMIT: $EVAL_LIMIT"
|
||||
|
||||
@@ -4,7 +4,7 @@ This folder contains evaluation for [WebArena](https://github.com/web-arena-x/we
|
||||
|
||||
## Setup Environment and LLM Configuration
|
||||
|
||||
Please follow instruction [here](../../README.md#setup) to setup your local development environment and LLM.
|
||||
Please follow instruction [here](../README.md#setup) to setup your local development environment and LLM.
|
||||
|
||||
## Setup WebArena Environment
|
||||
|
||||
|
||||
@@ -27,13 +27,13 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="BrowsingAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
EVAL_NOTE="$OPENHANDS_VERSION"
|
||||
EVAL_NOTE="$AGENT_VERSION"
|
||||
|
||||
COMMAND="poetry run python evaluation/benchmarks/webarena/run_infer.py \
|
||||
--agent-cls $AGENT \
|
||||
|
||||
@@ -21,13 +21,13 @@ if [ -z "$AGENT" ]; then
|
||||
AGENT="CodeActAgent"
|
||||
fi
|
||||
|
||||
get_openhands_version
|
||||
get_agent_version
|
||||
|
||||
echo "AGENT: $AGENT"
|
||||
echo "OPENHANDS_VERSION: $OPENHANDS_VERSION"
|
||||
echo "AGENT_VERSION: $AGENT_VERSION"
|
||||
echo "MODEL_CONFIG: $MODEL_CONFIG"
|
||||
|
||||
EVAL_NOTE=$OPENHANDS_VERSION
|
||||
EVAL_NOTE=$AGENT_VERSION
|
||||
|
||||
# Default to NOT use unit tests.
|
||||
if [ -z "$USE_UNIT_TESTS" ]; then
|
||||
|
||||
@@ -39,8 +39,8 @@ checkout_original_branch() {
|
||||
git checkout $current_branch
|
||||
}
|
||||
|
||||
get_openhands_version() {
|
||||
get_agent_version() {
|
||||
# IMPORTANT: Because Agent's prompt changes fairly often in the rapidly evolving codebase of OpenHands
|
||||
# We need to track the version of Agent in the evaluation to make sure results are comparable
|
||||
OPENHANDS_VERSION=v$(poetry run python -c "from openhands import get_version; print(get_version())")
|
||||
AGENT_VERSION=v$(poetry run python -c "import openhands.agenthub; from openhands.controller.agent import Agent; print(Agent.get_cls('$AGENT').VERSION)")
|
||||
}
|
||||
|
||||
1
frontend/.gitignore
vendored
1
frontend/.gitignore
vendored
@@ -7,4 +7,3 @@ node_modules/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
.react-router/
|
||||
|
||||
@@ -9,7 +9,6 @@ This is the frontend of the OpenHands project. It is a React application that pr
|
||||
- Remix SPA Mode (React + Vite + React Router)
|
||||
- TypeScript
|
||||
- Redux
|
||||
- TanStack Query
|
||||
- Tailwind CSS
|
||||
- i18next
|
||||
- React Testing Library
|
||||
@@ -86,7 +85,7 @@ frontend
|
||||
├── src
|
||||
│ ├── api # API calls
|
||||
│ ├── assets
|
||||
│ ├── components
|
||||
│ ├── components # Reusable components
|
||||
│ ├── context # Local state management
|
||||
│ ├── hooks # Custom hooks
|
||||
│ ├── i18n # Internationalization
|
||||
@@ -100,18 +99,6 @@ frontend
|
||||
└── .env.sample # Sample environment variables
|
||||
```
|
||||
|
||||
#### Components
|
||||
|
||||
Components are organized into folders based on their **domain**, **feature**, or **shared functionality**.
|
||||
|
||||
```sh
|
||||
components
|
||||
├── features # Domain-specific components
|
||||
├── layout
|
||||
├── modals
|
||||
└── ui # Shared UI components
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
- Real-time updates with WebSockets
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { screen } from "@testing-library/react";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithProviders } from "../../test-utils";
|
||||
import { BrowserPanel } from "#/components/features/browser/browser";
|
||||
|
||||
import BrowserPanel from "#/components/browser";
|
||||
|
||||
describe("Browser", () => {
|
||||
it("renders a message if no screenshotSrc is provided", () => {
|
||||
@@ -11,7 +10,6 @@ describe("Browser", () => {
|
||||
browser: {
|
||||
url: "https://example.com",
|
||||
screenshotSrc: "",
|
||||
updateCount: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -27,7 +25,6 @@ describe("Browser", () => {
|
||||
url: "https://example.com",
|
||||
screenshotSrc:
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN0uGvyHwAFCAJS091fQwAAAABJRU5ErkJggg==",
|
||||
updateCount: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, it, expect, test } from "vitest";
|
||||
import { ChatMessage } from "#/components/features/chat/chat-message";
|
||||
import { ChatMessage } from "#/components/chat-message";
|
||||
|
||||
describe("ChatMessage", () => {
|
||||
it("should render a user message", () => {
|
||||
@@ -70,12 +70,4 @@ describe("ChatMessage", () => {
|
||||
);
|
||||
expect(screen.getByTestId("custom-component")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should apply correct styles to inline code", () => {
|
||||
render(<ChatMessage type="assistant" message="Here is some `inline code` text" />);
|
||||
const codeElement = screen.getByText("inline code");
|
||||
|
||||
expect(codeElement.tagName.toLowerCase()).toBe("code");
|
||||
expect(codeElement.closest("article")).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { describe, afterEach, vi, it, expect } from "vitest";
|
||||
import { ChatInput } from "#/components/features/chat/chat-input";
|
||||
import { ChatInput } from "#/components/chat-input";
|
||||
|
||||
describe("ChatInput", () => {
|
||||
const onSubmitMock = vi.fn();
|
||||
|
||||
@@ -6,10 +6,10 @@ import { addUserMessage } from "#/state/chat-slice";
|
||||
import { SUGGESTIONS } from "#/utils/suggestions";
|
||||
import * as ChatSlice from "#/state/chat-slice";
|
||||
import { WsClientProviderStatus } from "#/context/ws-client-provider";
|
||||
import { ChatInterface } from "#/components/features/chat/chat-interface";
|
||||
import { ChatInterface } from "#/routes/_oh.app/chat-interface";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const renderChatInterface = (messages: (Message)[]) =>
|
||||
const renderChatInterface = (messages: (Message | ErrorMessage)[]) =>
|
||||
renderWithProviders(<ChatInterface />);
|
||||
|
||||
describe("Empty state", () => {
|
||||
@@ -26,8 +26,8 @@ describe("Empty state", () => {
|
||||
}));
|
||||
|
||||
beforeAll(() => {
|
||||
vi.mock("react-router", async (importActual) => ({
|
||||
...(await importActual<typeof import("react-router")>()),
|
||||
vi.mock("@remix-run/react", async (importActual) => ({
|
||||
...(await importActual<typeof import("@remix-run/react")>()),
|
||||
useRouteLoaderData: vi.fn(() => ({})),
|
||||
}));
|
||||
|
||||
@@ -56,7 +56,6 @@ describe("Empty state", () => {
|
||||
content: "Hello",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -173,14 +172,12 @@ describe.skip("ChatInterface", () => {
|
||||
content: "Hello",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
{
|
||||
sender: "assistant",
|
||||
content: "Hi",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
];
|
||||
renderChatInterface(messages);
|
||||
@@ -214,7 +211,6 @@ describe.skip("ChatInterface", () => {
|
||||
content: "Here are some images",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
];
|
||||
const { rerender } = renderChatInterface(messages);
|
||||
@@ -227,7 +223,6 @@ describe.skip("ChatInterface", () => {
|
||||
content: "Here are some images",
|
||||
imageUrls: ["image1", "image2"],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -249,14 +244,12 @@ describe.skip("ChatInterface", () => {
|
||||
content: "Hello",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
{
|
||||
sender: "user",
|
||||
content: "Hi",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
];
|
||||
const { rerender } = renderChatInterface(messages);
|
||||
@@ -269,7 +262,6 @@ describe.skip("ChatInterface", () => {
|
||||
content: "How can I help you?",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
});
|
||||
|
||||
rerender(<ChatInterface />);
|
||||
@@ -278,19 +270,17 @@ describe.skip("ChatInterface", () => {
|
||||
});
|
||||
|
||||
it("should render inline errors", () => {
|
||||
const messages: (Message)[] = [
|
||||
const messages: (Message | ErrorMessage)[] = [
|
||||
{
|
||||
sender: "assistant",
|
||||
content: "Hello",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
{
|
||||
type: "error",
|
||||
content: "Something went wrong",
|
||||
sender: "assistant",
|
||||
timestamp: new Date().toISOString(),
|
||||
error: true,
|
||||
id: "",
|
||||
message: "Something went wrong",
|
||||
},
|
||||
];
|
||||
renderChatInterface(messages);
|
||||
@@ -300,8 +290,8 @@ describe.skip("ChatInterface", () => {
|
||||
});
|
||||
|
||||
it("should render both GitHub buttons initially when ghToken is available", () => {
|
||||
vi.mock("react-router", async (importActual) => ({
|
||||
...(await importActual<typeof import("react-router")>()),
|
||||
vi.mock("@remix-run/react", async (importActual) => ({
|
||||
...(await importActual<typeof import("@remix-run/react")>()),
|
||||
useRouteLoaderData: vi.fn(() => ({ ghToken: "test-token" })),
|
||||
}));
|
||||
|
||||
@@ -311,7 +301,6 @@ describe.skip("ChatInterface", () => {
|
||||
content: "Hello",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
];
|
||||
renderChatInterface(messages);
|
||||
@@ -326,8 +315,8 @@ describe.skip("ChatInterface", () => {
|
||||
});
|
||||
|
||||
it("should render only 'Push changes to PR' button after PR is created", async () => {
|
||||
vi.mock("react-router", async (importActual) => ({
|
||||
...(await importActual<typeof import("react-router")>()),
|
||||
vi.mock("@remix-run/react", async (importActual) => ({
|
||||
...(await importActual<typeof import("@remix-run/react")>()),
|
||||
useRouteLoaderData: vi.fn(() => ({ ghToken: "test-token" })),
|
||||
}));
|
||||
|
||||
@@ -337,7 +326,6 @@ describe.skip("ChatInterface", () => {
|
||||
content: "Hello",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
];
|
||||
const { rerender } = renderChatInterface(messages);
|
||||
@@ -370,21 +358,18 @@ describe.skip("ChatInterface", () => {
|
||||
content: "Hello",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
{
|
||||
sender: "user",
|
||||
content: "Hi",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
{
|
||||
sender: "assistant",
|
||||
content: "How can I help you?",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
},
|
||||
];
|
||||
const { rerender } = renderChatInterface(messages);
|
||||
@@ -395,7 +380,6 @@ describe.skip("ChatInterface", () => {
|
||||
content: "I need help",
|
||||
imageUrls: [],
|
||||
timestamp: new Date().toISOString(),
|
||||
pending: true,
|
||||
});
|
||||
|
||||
rerender(<ChatInterface />);
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { screen } from "@testing-library/react";
|
||||
import { renderWithProviders } from "test-utils";
|
||||
import { ExpandableMessage } from "#/components/features/chat/expandable-message";
|
||||
|
||||
describe("ExpandableMessage", () => {
|
||||
it("should render with neutral border for non-action messages", () => {
|
||||
renderWithProviders(<ExpandableMessage message="Hello" type="thought" />);
|
||||
const element = screen.getByText("Hello");
|
||||
const container = element.closest("div.flex.gap-2.items-center.justify-between");
|
||||
expect(container).toHaveClass("border-neutral-300");
|
||||
expect(screen.queryByTestId("status-icon")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render with neutral border for error messages", () => {
|
||||
renderWithProviders(<ExpandableMessage message="Error occurred" type="error" />);
|
||||
const element = screen.getByText("Error occurred");
|
||||
const container = element.closest("div.flex.gap-2.items-center.justify-between");
|
||||
expect(container).toHaveClass("border-neutral-300");
|
||||
expect(screen.queryByTestId("status-icon")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render with success icon for successful action messages", () => {
|
||||
renderWithProviders(
|
||||
<ExpandableMessage
|
||||
message="Command executed successfully"
|
||||
type="action"
|
||||
success={true}
|
||||
/>
|
||||
);
|
||||
const element = screen.getByText("Command executed successfully");
|
||||
const container = element.closest("div.flex.gap-2.items-center.justify-between");
|
||||
expect(container).toHaveClass("border-neutral-300");
|
||||
const icon = screen.getByTestId("status-icon");
|
||||
expect(icon).toHaveClass("fill-success");
|
||||
});
|
||||
|
||||
it("should render with error icon for failed action messages", () => {
|
||||
renderWithProviders(
|
||||
<ExpandableMessage
|
||||
message="Command failed"
|
||||
type="action"
|
||||
success={false}
|
||||
/>
|
||||
);
|
||||
const element = screen.getByText("Command failed");
|
||||
const container = element.closest("div.flex.gap-2.items-center.justify-between");
|
||||
expect(container).toHaveClass("border-neutral-300");
|
||||
const icon = screen.getByTestId("status-icon");
|
||||
expect(icon).toHaveClass("fill-danger");
|
||||
});
|
||||
|
||||
it("should render with neutral border and no icon for action messages without success prop", () => {
|
||||
renderWithProviders(<ExpandableMessage message="Running command" type="action" />);
|
||||
const element = screen.getByText("Running command");
|
||||
const container = element.closest("div.flex.gap-2.items-center.justify-between");
|
||||
expect(container).toHaveClass("border-neutral-300");
|
||||
expect(screen.queryByTestId("status-icon")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { afterEach, describe, expect, it, test, vi } from "vitest";
|
||||
import { AccountSettingsContextMenu } from "#/components/features/context-menu/account-settings-context-menu";
|
||||
import { AccountSettingsContextMenu } from "#/components/context-menu/account-settings-context-menu";
|
||||
|
||||
describe("AccountSettingsContextMenu", () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { ContextMenuListItem } from "#/components/features/context-menu/context-menu-list-item";
|
||||
import { ContextMenuListItem } from "#/components/context-menu/context-menu-list-item";
|
||||
|
||||
describe("ContextMenuListItem", () => {
|
||||
it("should render the component with the children", () => {
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { it, describe, expect, vi } from "vitest";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { WaitlistModal } from "#/components/features/waitlist/waitlist-modal";
|
||||
import * as CaptureConsent from "#/utils/handle-capture-consent";
|
||||
|
||||
describe("WaitlistModal", () => {
|
||||
it("should render a tos checkbox that is unchecked by default", () => {
|
||||
render(<WaitlistModal ghToken={null} githubAuthUrl={null} />);
|
||||
const checkbox = screen.getByRole("checkbox");
|
||||
|
||||
expect(checkbox).not.toBeChecked();
|
||||
});
|
||||
|
||||
it("should only enable the GitHub button if the tos checkbox is checked", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<WaitlistModal ghToken={null} githubAuthUrl={null} />);
|
||||
const checkbox = screen.getByRole("checkbox");
|
||||
const button = screen.getByRole("button", { name: "Connect to GitHub" });
|
||||
|
||||
expect(button).toBeDisabled();
|
||||
|
||||
await user.click(checkbox);
|
||||
|
||||
expect(button).not.toBeDisabled();
|
||||
});
|
||||
|
||||
it("should set user analytics consent to true when the user checks the tos checkbox", async () => {
|
||||
const handleCaptureConsentSpy = vi.spyOn(
|
||||
CaptureConsent,
|
||||
"handleCaptureConsent",
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<WaitlistModal ghToken={null} githubAuthUrl="mock-url" />);
|
||||
|
||||
const checkbox = screen.getByRole("checkbox");
|
||||
await user.click(checkbox);
|
||||
|
||||
const button = screen.getByRole("button", { name: "Connect to GitHub" });
|
||||
await user.click(button);
|
||||
|
||||
expect(handleCaptureConsentSpy).toHaveBeenCalledWith(true);
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { render, screen, within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { FeedbackActions } from "#/components/features/feedback/feedback-actions";
|
||||
import { FeedbackActions } from "#/components/feedback-actions";
|
||||
|
||||
describe("FeedbackActions", () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { screen } from "@testing-library/react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { renderWithProviders } from "test-utils";
|
||||
import { FeedbackForm } from "#/components/features/feedback/feedback-form";
|
||||
import { FeedbackForm } from "#/components/feedback-form";
|
||||
|
||||
describe("FeedbackForm", () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { screen } from "@testing-library/react";
|
||||
import { renderWithProviders } from "test-utils";
|
||||
import { describe, afterEach, vi, it, expect } from "vitest";
|
||||
import { ExplorerTree } from "#/components/features/file-explorer/explorer-tree";
|
||||
import ExplorerTree from "#/components/file-explorer/explorer-tree";
|
||||
|
||||
const FILES = ["file-1-1.ts", "folder-1-2"];
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import { renderWithProviders } from "test-utils";
|
||||
import { describe, it, expect, vi, Mock, afterEach } from "vitest";
|
||||
import toast from "#/utils/toast";
|
||||
import AgentState from "#/types/agent-state";
|
||||
import { FileExplorer } from "#/routes/_oh.app._index/file-explorer/file-explorer";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
import { FileExplorer } from "#/components/features/file-explorer/file-explorer";
|
||||
|
||||
const toastSpy = vi.spyOn(toast, "error");
|
||||
const uploadFilesSpy = vi.spyOn(OpenHands, "uploadFiles");
|
||||
|
||||
@@ -2,7 +2,7 @@ import { screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { renderWithProviders } from "test-utils";
|
||||
import { vi, describe, afterEach, it, expect } from "vitest";
|
||||
import TreeNode from "#/components/features/file-explorer/tree-node";
|
||||
import TreeNode from "#/components/file-explorer/tree-node";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
|
||||
const getFileSpy = vi.spyOn(OpenHands, "getFile");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ImagePreview } from "#/components/features/images/image-preview";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { ImagePreview } from "#/components/image-preview";
|
||||
|
||||
describe("ImagePreview", () => {
|
||||
it("should render an image", () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { render, screen, within, fireEvent } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { InteractiveChatBox } from "#/components/features/chat/interactive-chat-box";
|
||||
import { InteractiveChatBox } from "#/components/interactive-chat-box";
|
||||
|
||||
describe("InteractiveChatBox", () => {
|
||||
const onSubmitMock = vi.fn();
|
||||
@@ -98,6 +98,33 @@ describe("InteractiveChatBox", () => {
|
||||
expect(screen.queryAllByTestId("image-preview")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should clear text input after submitting with images via paste", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<InteractiveChatBox onSubmit={onSubmitMock} onStop={onStopMock} />);
|
||||
|
||||
const textarea = within(screen.getByTestId("chat-input")).getByRole(
|
||||
"textbox",
|
||||
);
|
||||
await user.type(textarea, "Hello, world!");
|
||||
|
||||
const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" });
|
||||
|
||||
// Get the UploadImageInput component and simulate file upload
|
||||
const input = screen.getByTestId("upload-image-input");
|
||||
const changeEvent = {
|
||||
target: {
|
||||
files: [file],
|
||||
},
|
||||
};
|
||||
fireEvent.change(input, changeEvent);
|
||||
|
||||
// Submit the message
|
||||
await user.keyboard("{Enter}");
|
||||
|
||||
expect(onSubmitMock).toHaveBeenCalledWith("Hello, world!", [file]);
|
||||
expect(textarea).toHaveValue("");
|
||||
});
|
||||
|
||||
it("should disable the submit button", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
@@ -131,60 +158,4 @@ describe("InteractiveChatBox", () => {
|
||||
await user.click(stopButton);
|
||||
expect(onStopMock).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("should handle image upload and message submission correctly", async () => {
|
||||
const user = userEvent.setup();
|
||||
const onSubmit = vi.fn();
|
||||
const onStop = vi.fn();
|
||||
const onChange = vi.fn();
|
||||
|
||||
const { rerender } = render(
|
||||
<InteractiveChatBox
|
||||
onSubmit={onSubmit}
|
||||
onStop={onStop}
|
||||
onChange={onChange}
|
||||
value="test message"
|
||||
/>
|
||||
);
|
||||
|
||||
// Upload an image via the upload button - this should NOT clear the text input
|
||||
const file = new File(["dummy content"], "test.png", { type: "image/png" });
|
||||
const input = screen.getByTestId("upload-image-input");
|
||||
await user.upload(input, file);
|
||||
|
||||
// Verify text input was not cleared
|
||||
expect(screen.getByRole("textbox")).toHaveValue("test message");
|
||||
expect(onChange).not.toHaveBeenCalledWith("");
|
||||
|
||||
// Submit the message with image
|
||||
const submitButton = screen.getByRole("button", { name: "Send" });
|
||||
await user.click(submitButton);
|
||||
|
||||
// Verify onSubmit was called with the message and image
|
||||
expect(onSubmit).toHaveBeenCalledWith("test message", [file]);
|
||||
|
||||
// Verify onChange was called to clear the text input
|
||||
expect(onChange).toHaveBeenCalledWith("");
|
||||
|
||||
// Simulate parent component updating the value prop
|
||||
rerender(
|
||||
<InteractiveChatBox
|
||||
onSubmit={onSubmit}
|
||||
onStop={onStop}
|
||||
onChange={onChange}
|
||||
value=""
|
||||
/>
|
||||
);
|
||||
|
||||
// Verify the text input was cleared
|
||||
expect(screen.getByRole("textbox")).toHaveValue("");
|
||||
|
||||
// Upload another image - this should NOT clear the text input
|
||||
onChange.mockClear();
|
||||
await user.upload(input, file);
|
||||
|
||||
// Verify text input is still empty and onChange was not called
|
||||
expect(screen.getByRole("textbox")).toHaveValue("");
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { render, screen, act } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, it, vi, expect } from "vitest";
|
||||
import { BaseModal } from "#/components/shared/modals/base-modal/base-modal";
|
||||
import BaseModal from "#/components/modals/base-modal/base-modal";
|
||||
|
||||
describe("BaseModal", () => {
|
||||
it("should render if the modal is open", () => {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user