Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
SmartManoj committed Nov 21, 2024
2 parents 639553d + 12ed523 commit 6cfe42e
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 17 deletions.
7 changes: 2 additions & 5 deletions .github/workflows/lint-fix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,8 @@ jobs:
run: pip install pre-commit==3.7.0
- name: Fix python lint issues
run: |
pre-commit run trailing-whitespace --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml
pre-commit run end-of-file-fixer --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml
pre-commit run pyproject-fmt --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml
pre-commit run ruff --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml
pre-commit run ruff-format --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml
# Run all pre-commit hooks and continue even if they modify files (exit code 1)
pre-commit run --config ./dev_config/python/.pre-commit-config.yaml --files openhands/**/* evaluation/**/* tests/**/* || true
# Commit and push changes if any
- name: Check for changes
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/openhands-resolver.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ jobs:
github.event.label.name == 'fix-me-experimental' ||
(
(github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') &&
startsWith(github.event.comment.body, inputs.macro || '@openhands-agent-exp')
startsWith(github.event.comment.body, '@openhands-agent-exp')
) ||
(
github.event_name == 'pull_request_review' &&
startsWith(github.event.review.body, inputs.macro || '@openhands-agent-exp')
startsWith(github.event.review.body, '@openhands-agent-exp')
)
)
uses: actions/cache@v3
Expand Down
50 changes: 50 additions & 0 deletions docs/modules/usage/how-to/github-action.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,53 @@ To customize the default macro (`@openhands-agent`):

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

The `.openhands_instructions` file is a file that you can put in the root directory of your repository to guide OpenHands in understanding and working with your repository effectively. Here are key tips for writing high-quality instructions:

### Core Principles

1. **Concise but Informative**: Provide a clear, focused overview of the repository that emphasizes the most common actions OpenHands will need to perform.

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
- Any environment-specific requirements

4. **Testing Guidelines**: Specify:
- Where tests are located
- How to run specific test suites
- Any testing conventions or requirements

### Example Structure

```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
```

For a real-world example, refer to the [OpenHands repository's .openhands_instructions](https://github.com/All-Hands-AI/OpenHands/blob/main/.openhands_instructions).
2 changes: 1 addition & 1 deletion openhands/llm/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ def is_hallucination(text) -> bool:
)
def wrapper(*args, **kwargs):
"""Wrapper for the litellm completion function. Logs the input and output of the completion function."""

messages: list[Message] | Message = []

mock_function_calling = kwargs.pop('mock_function_calling', False)

# some callers might send the model and messages directly
Expand Down
5 changes: 5 additions & 0 deletions openhands/resolver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Follow these steps to use this workflow in your own repository:

1. [Create a personal access token](https://github.com/settings/tokens?type=beta) with read/write scope for "contents", "issues", "pull requests", and "workflows"

Note: If you're working with an organizational repository, you may need to configure the organization's personal access token policy first. See [Setting a personal access token policy for your organization](https://docs.github.com/en/organizations/managing-programmatic-access-to-your-organization/setting-a-personal-access-token-policy-for-your-organization) for details.

2. Create an API key for the [Claude API](https://www.anthropic.com/api) (recommended) or another supported LLM service

3. Copy `examples/openhands-resolver.yml` to your repository's `.github/workflows/` directory
Expand Down Expand Up @@ -83,11 +85,14 @@ pip install openhands-ai
3. Set up environment variables:

```bash

# GitHub credentials

export GITHUB_TOKEN="your-github-token"
export GITHUB_USERNAME="your-github-username" # Optional, defaults to token owner

# LLM configuration

export LLM_MODEL="anthropic/claude-3-5-sonnet-20241022" # Recommended
export LLM_API_KEY="your-llm-api-key"
export LLM_BASE_URL="your-api-url" # Optional, for API proxies
Expand Down
64 changes: 55 additions & 9 deletions openhands/server/listen.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
from openhands.events.serialization import event_to_dict
from openhands.events.stream import AsyncEventStreamWrapper
from openhands.llm import bedrock
from openhands.runtime.base import Runtime
from openhands.runtime.base import Runtime, RuntimeUnavailableError
from openhands.server.auth.auth import get_sid_from_token, sign_token
from openhands.server.middleware import (
InMemoryRateLimiter,
Expand Down Expand Up @@ -517,7 +517,14 @@ async def list_files(request: Request, path: str | None = None):
)

runtime: Runtime = request.state.conversation.runtime
file_list = await call_sync_from_async(runtime.list_files, path)
try:
file_list = await call_sync_from_async(runtime.list_files, path)
except RuntimeUnavailableError as e:
logger.error(f'Error listing files: {e}', exc_info=True)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={'error': f'Error listing files: {e}'},
)
if path:
file_list = [os.path.join(path, f) for f in file_list]

Expand All @@ -537,7 +544,14 @@ async def filter_for_gitignore(file_list, base_path):
file_list = [entry for entry in file_list if not spec.match_file(entry)]
return file_list

file_list = await filter_for_gitignore(file_list, '')
try:
file_list = await filter_for_gitignore(file_list, '')
except RuntimeUnavailableError as e:
logger.error(f'Error filtering files: {e}', exc_info=True)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={'error': f'Error filtering files: {e}'},
)

return file_list

Expand Down Expand Up @@ -566,7 +580,14 @@ async def select_file(file: str, request: Request):

file = os.path.join(runtime.config.workspace_mount_path_in_sandbox, file)
read_action = FileReadAction(file)
observation = await call_sync_from_async(runtime.run_action, read_action)
try:
observation = await call_sync_from_async(runtime.run_action, read_action)
except RuntimeUnavailableError as e:
logger.error(f'Error opening file {file}: {e}', exc_info=True)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={'error': f'Error opening file: {e}'},
)

if isinstance(observation, FileReadObservation):
content = observation.content
Expand Down Expand Up @@ -662,9 +683,20 @@ async def upload_file(request: Request, files: list[UploadFile]):
tmp_file.flush()

runtime: Runtime = request.state.conversation.runtime
runtime.copy_to(
tmp_file_path, runtime.config.workspace_mount_path_in_sandbox
)
try:
await call_sync_from_async(
runtime.copy_to,
tmp_file_path,
runtime.config.workspace_mount_path_in_sandbox,
)
except RuntimeUnavailableError as e:
logger.error(
f'Error saving file {safe_filename}: {e}', exc_info=True
)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={'error': f'Error saving file: {e}'},
)
uploaded_files.append(safe_filename)

response_content = {
Expand Down Expand Up @@ -795,7 +827,14 @@ async def save_file(request: Request):
runtime.config.workspace_mount_path_in_sandbox, file_path
)
write_action = FileWriteAction(file_path, content)
observation = await call_sync_from_async(runtime.run_action, write_action)
try:
observation = await call_sync_from_async(runtime.run_action, write_action)
except RuntimeUnavailableError as e:
logger.error(f'Error saving file: {e}', exc_info=True)
return JSONResponse(
status_code=500,
content={'error': f'Error saving file: {e}'},
)

if isinstance(observation, FileWriteObservation):
return JSONResponse(
Expand Down Expand Up @@ -846,7 +885,14 @@ async def zip_current_workspace(request: Request, background_tasks: BackgroundTa
logger.debug('Zipping workspace')
runtime: Runtime = request.state.conversation.runtime
path = runtime.config.workspace_mount_path_in_sandbox
zip_file = await call_sync_from_async(runtime.copy_from, path)
try:
zip_file = await call_sync_from_async(runtime.copy_from, path)
except RuntimeUnavailableError as e:
logger.error(f'Error zipping workspace: {e}', exc_info=True)
return JSONResponse(
status_code=500,
content={'error': f'Error zipping workspace: {e}'},
)
response = FileResponse(
path=zip_file,
filename='workspace.zip',
Expand Down
3 changes: 3 additions & 0 deletions openhands/server/session/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ def close(self):
self.websocket = None
finally:
self.agent_session.close()
del (
self.agent_session
) # FIXME: this should not be necessary but it mitigates a memory leak

async def loop_recv(self):
try:
Expand Down

0 comments on commit 6cfe42e

Please sign in to comment.