mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-04-29 03:00:45 -04:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e79cc6517e | |||
| 5c6bf5f7a0 |
@@ -0,0 +1,123 @@
|
|||||||
|
# OpenHands GitHub Actions Workflow Templates
|
||||||
|
|
||||||
|
This directory contains workflow templates that make it easy to integrate OpenHands AI agent into your GitHub CI/CD workflows.
|
||||||
|
|
||||||
|
## Available Templates
|
||||||
|
|
||||||
|
### 1. OpenHands Code Review (`openhands-code-review.yml`)
|
||||||
|
Automatically reviews pull requests for code quality, security, and best practices.
|
||||||
|
|
||||||
|
**Triggers:** Pull request opened or updated
|
||||||
|
**Permissions:** `contents: read`, `pull-requests: write`, `issues: write`
|
||||||
|
|
||||||
|
### 2. OpenHands Bug Fix (`openhands-bug-fix.yml`)
|
||||||
|
Automatically investigates and fixes bugs when issues are labeled with 'bug'.
|
||||||
|
|
||||||
|
**Triggers:** Issue labeled with 'bug'
|
||||||
|
**Permissions:** `contents: write`, `pull-requests: write`, `issues: write`
|
||||||
|
|
||||||
|
### 3. OpenHands Documentation (`openhands-documentation.yml`)
|
||||||
|
Keeps project documentation up-to-date by reviewing code changes and updating docs.
|
||||||
|
|
||||||
|
**Triggers:** Weekly schedule, manual dispatch, or code changes
|
||||||
|
**Permissions:** `contents: write`, `pull-requests: write`
|
||||||
|
|
||||||
|
### 4. OpenHands Custom Task (`openhands-custom-task.yml`)
|
||||||
|
Run any custom development task with a manual trigger and custom description.
|
||||||
|
|
||||||
|
**Triggers:** Manual dispatch with task description input
|
||||||
|
**Permissions:** `contents: write`, `pull-requests: write`, `issues: write`
|
||||||
|
|
||||||
|
## Setup Instructions
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
1. **OpenHands API Key**: Get your API key from [OpenHands](https://app.all-hands.dev)
|
||||||
|
2. **GitHub Repository**: The templates work with any GitHub repository
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
1. **Add API Key Secret**:
|
||||||
|
- Go to your repository's Settings → Secrets and variables → Actions
|
||||||
|
- Add a new repository secret named `OPENHANDS_API_KEY`
|
||||||
|
- Set the value to your OpenHands API key
|
||||||
|
|
||||||
|
2. **Use Templates**:
|
||||||
|
- Go to your repository's Actions tab
|
||||||
|
- Click "New workflow"
|
||||||
|
- Look for "OpenHands" templates in the template gallery
|
||||||
|
- Choose the template that fits your needs
|
||||||
|
- Customize as needed and commit
|
||||||
|
|
||||||
|
### Customization
|
||||||
|
|
||||||
|
All templates can be customized:
|
||||||
|
|
||||||
|
- **Prompts**: Modify the task descriptions to fit your specific needs
|
||||||
|
- **Triggers**: Change when workflows run (schedule, events, manual)
|
||||||
|
- **Timeouts**: Adjust polling timeouts based on task complexity
|
||||||
|
- **Permissions**: Modify based on what actions OpenHands needs to perform
|
||||||
|
|
||||||
|
### Example Customizations
|
||||||
|
|
||||||
|
#### Custom Review Criteria
|
||||||
|
```yaml
|
||||||
|
prompt = '''Please review this pull request focusing on:
|
||||||
|
- Performance optimization opportunities
|
||||||
|
- Database query efficiency
|
||||||
|
- API design consistency
|
||||||
|
- Error handling completeness
|
||||||
|
'''
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Specific Documentation Updates
|
||||||
|
```yaml
|
||||||
|
prompt = '''Update the following documentation:
|
||||||
|
1. API reference in docs/api.md
|
||||||
|
2. Installation guide in README.md
|
||||||
|
3. Code examples in docs/examples/
|
||||||
|
'''
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **Workflow Trigger**: GitHub event triggers the workflow
|
||||||
|
2. **Setup**: Installs Python and downloads the OpenHands API helper
|
||||||
|
3. **API Call**: Creates a conversation with OpenHands using your prompt
|
||||||
|
4. **Execution**: OpenHands performs the requested task in your repository
|
||||||
|
5. **Results**: OpenHands may create PRs, comments, or other outputs
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
- **API Key**: Keep your `OPENHANDS_API_KEY` secret secure
|
||||||
|
- **Permissions**: Templates request minimal required permissions
|
||||||
|
- **Repository Access**: OpenHands will have access to your repository during task execution
|
||||||
|
- **Review Changes**: Always review any PRs or changes made by OpenHands
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Missing API Key**: Ensure `OPENHANDS_API_KEY` is set in repository secrets
|
||||||
|
2. **Permission Errors**: Check that workflow permissions match template requirements
|
||||||
|
3. **Timeout Issues**: Increase timeout values for complex tasks
|
||||||
|
4. **Rate Limits**: OpenHands API has rate limits; space out workflow runs if needed
|
||||||
|
|
||||||
|
### Getting Help
|
||||||
|
|
||||||
|
- Check the [OpenHands Documentation](https://docs.all-hands.dev)
|
||||||
|
- Review workflow run logs for detailed error messages
|
||||||
|
- Ensure your repository is accessible and has the necessary permissions
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
To improve these templates:
|
||||||
|
|
||||||
|
1. Test changes thoroughly
|
||||||
|
2. Update documentation
|
||||||
|
3. Follow GitHub Actions best practices
|
||||||
|
4. Consider security implications
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
These templates are provided under the same license as the OpenHands project.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "OpenHands Bug Fix",
|
||||||
|
"description": "Automatically investigate and fix bugs using OpenHands AI agent. Triggered when issues are labeled with 'bug'.",
|
||||||
|
"iconName": "octicon bug",
|
||||||
|
"categories": [
|
||||||
|
"Bug Fix",
|
||||||
|
"AI",
|
||||||
|
"Automation",
|
||||||
|
"Debugging"
|
||||||
|
],
|
||||||
|
"filePatterns": [
|
||||||
|
".*\\.py$",
|
||||||
|
".*\\.js$",
|
||||||
|
".*\\.ts$",
|
||||||
|
".*\\.jsx$",
|
||||||
|
".*\\.tsx$",
|
||||||
|
".*\\.java$",
|
||||||
|
".*\\.go$",
|
||||||
|
".*\\.rs$",
|
||||||
|
".*\\.cpp$",
|
||||||
|
".*\\.c$"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
name: OpenHands Bug Fix
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [labeled]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
openhands-fix:
|
||||||
|
if: contains(github.event.label.name, 'bug')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install OpenHands API helper
|
||||||
|
run: |
|
||||||
|
curl -O https://raw.githubusercontent.com/All-Hands-AI/OpenHands/main/scripts/openhands_api.py
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install requests
|
||||||
|
|
||||||
|
- name: Run OpenHands Bug Fix
|
||||||
|
env:
|
||||||
|
OPENHANDS_API_KEY: ${{ secrets.OPENHANDS_API_KEY }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
python -c "
|
||||||
|
import sys
|
||||||
|
sys.path.append('.')
|
||||||
|
from openhands_api import OpenHandsAPI
|
||||||
|
|
||||||
|
# Create bug fix prompt
|
||||||
|
prompt = '''Please investigate and fix the bug described in this GitHub issue:
|
||||||
|
|
||||||
|
Repository: ${{ github.repository }}
|
||||||
|
Issue: #${{ github.event.issue.number }}
|
||||||
|
Title: ${{ github.event.issue.title }}
|
||||||
|
|
||||||
|
Issue Description:
|
||||||
|
${{ github.event.issue.body }}
|
||||||
|
|
||||||
|
Please:
|
||||||
|
1. Analyze the issue and identify the root cause
|
||||||
|
2. Implement a fix with proper error handling
|
||||||
|
3. Add or update tests to prevent regression
|
||||||
|
4. Create a pull request with your changes
|
||||||
|
5. Include a clear description of what was fixed and how
|
||||||
|
|
||||||
|
Make sure to follow the project'\''s coding standards and best practices.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Start OpenHands conversation
|
||||||
|
client = OpenHandsAPI()
|
||||||
|
response = client.create_conversation(
|
||||||
|
initial_user_msg=prompt,
|
||||||
|
repository='${{ github.repository }}'
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f'Started OpenHands bug fix: {response.get(\"conversation_id\", \"Unknown\")}')
|
||||||
|
|
||||||
|
# Poll for completion (optional - remove if you want fire-and-forget)
|
||||||
|
try:
|
||||||
|
final_response = client.poll_until_stopped(response['conversation_id'], timeout=1200)
|
||||||
|
print(f'Bug fix completed with status: {final_response.get(\"status\", \"Unknown\")}')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Bug fix may still be running: {e}')
|
||||||
|
"
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "OpenHands Code Review",
|
||||||
|
"description": "Automated code review using OpenHands AI agent. Reviews PRs for code quality, security, and best practices.",
|
||||||
|
"iconName": "octicon code-review",
|
||||||
|
"categories": [
|
||||||
|
"Code Quality",
|
||||||
|
"AI",
|
||||||
|
"Automation",
|
||||||
|
"Python",
|
||||||
|
"JavaScript",
|
||||||
|
"TypeScript"
|
||||||
|
],
|
||||||
|
"filePatterns": [
|
||||||
|
".*\\.py$",
|
||||||
|
".*\\.js$",
|
||||||
|
".*\\.ts$",
|
||||||
|
".*\\.jsx$",
|
||||||
|
".*\\.tsx$",
|
||||||
|
".*\\.java$",
|
||||||
|
".*\\.go$",
|
||||||
|
".*\\.rs$",
|
||||||
|
".*\\.cpp$",
|
||||||
|
".*\\.c$"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
name: OpenHands Code Review
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
openhands-review:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install OpenHands API helper
|
||||||
|
run: |
|
||||||
|
curl -O https://raw.githubusercontent.com/All-Hands-AI/OpenHands/main/scripts/openhands_api.py
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install requests
|
||||||
|
|
||||||
|
- name: Run OpenHands Code Review
|
||||||
|
env:
|
||||||
|
OPENHANDS_API_KEY: ${{ secrets.OPENHANDS_API_KEY }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
python -c "
|
||||||
|
import sys
|
||||||
|
sys.path.append('.')
|
||||||
|
from openhands_api import OpenHandsAPI
|
||||||
|
|
||||||
|
# Create review prompt
|
||||||
|
prompt = '''Please review this pull request for:
|
||||||
|
- Code quality and best practices
|
||||||
|
- Security vulnerabilities
|
||||||
|
- Performance considerations
|
||||||
|
- Documentation completeness
|
||||||
|
- Test coverage
|
||||||
|
|
||||||
|
Repository: ${{ github.repository }}
|
||||||
|
PR: #${{ github.event.number }}
|
||||||
|
Title: ${{ github.event.pull_request.title }}
|
||||||
|
|
||||||
|
Please provide constructive feedback and suggestions for improvement.
|
||||||
|
If you find any issues, please create a detailed comment explaining the problem and suggesting solutions.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Start OpenHands conversation
|
||||||
|
client = OpenHandsAPI()
|
||||||
|
response = client.create_conversation(
|
||||||
|
initial_user_msg=prompt,
|
||||||
|
repository='${{ github.repository }}'
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f'Started OpenHands review: {response.get(\"conversation_id\", \"Unknown\")}')
|
||||||
|
|
||||||
|
# Poll for completion (optional - remove if you want fire-and-forget)
|
||||||
|
try:
|
||||||
|
final_response = client.poll_until_stopped(response['conversation_id'], timeout=600)
|
||||||
|
print(f'Review completed with status: {final_response.get(\"status\", \"Unknown\")}')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Review may still be running: {e}')
|
||||||
|
"
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "OpenHands Custom Task",
|
||||||
|
"description": "Run any custom development task using OpenHands AI agent. Manually triggered with custom task description.",
|
||||||
|
"iconName": "octicon tools",
|
||||||
|
"categories": [
|
||||||
|
"AI",
|
||||||
|
"Automation",
|
||||||
|
"Custom",
|
||||||
|
"Development"
|
||||||
|
],
|
||||||
|
"filePatterns": [
|
||||||
|
".*"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
name: OpenHands Custom Task
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
task_description:
|
||||||
|
description: 'Describe the task you want OpenHands to perform'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
timeout_minutes:
|
||||||
|
description: 'Timeout in minutes (default: 20)'
|
||||||
|
required: false
|
||||||
|
default: '20'
|
||||||
|
type: string
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
openhands-task:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install OpenHands API helper
|
||||||
|
run: |
|
||||||
|
curl -O https://raw.githubusercontent.com/All-Hands-AI/OpenHands/main/scripts/openhands_api.py
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install requests
|
||||||
|
|
||||||
|
- name: Run OpenHands Custom Task
|
||||||
|
env:
|
||||||
|
OPENHANDS_API_KEY: ${{ secrets.OPENHANDS_API_KEY }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
python -c "
|
||||||
|
import sys
|
||||||
|
sys.path.append('.')
|
||||||
|
from openhands_api import OpenHandsAPI
|
||||||
|
|
||||||
|
# Create custom task prompt
|
||||||
|
prompt = '''${{ github.event.inputs.task_description }}
|
||||||
|
|
||||||
|
Repository: ${{ github.repository }}
|
||||||
|
|
||||||
|
Please complete this task following best practices:
|
||||||
|
- Write clean, well-documented code
|
||||||
|
- Add appropriate tests if needed
|
||||||
|
- Follow the project'\''s coding standards
|
||||||
|
- Create a pull request if changes are made
|
||||||
|
- Provide clear explanations of what was done
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Start OpenHands conversation
|
||||||
|
client = OpenHandsAPI()
|
||||||
|
response = client.create_conversation(
|
||||||
|
initial_user_msg=prompt,
|
||||||
|
repository='${{ github.repository }}'
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f'Started OpenHands custom task: {response.get(\"conversation_id\", \"Unknown\")}')
|
||||||
|
|
||||||
|
# Poll for completion
|
||||||
|
timeout_seconds = int('${{ github.event.inputs.timeout_minutes }}') * 60
|
||||||
|
try:
|
||||||
|
final_response = client.poll_until_stopped(response['conversation_id'], timeout=timeout_seconds)
|
||||||
|
print(f'Custom task completed with status: {final_response.get(\"status\", \"Unknown\")}')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Custom task may still be running or timed out: {e}')
|
||||||
|
"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "OpenHands Documentation",
|
||||||
|
"description": "Automatically update and maintain project documentation using OpenHands AI agent. Runs weekly and on code changes.",
|
||||||
|
"iconName": "octicon book",
|
||||||
|
"categories": [
|
||||||
|
"Documentation",
|
||||||
|
"AI",
|
||||||
|
"Automation",
|
||||||
|
"Maintenance"
|
||||||
|
],
|
||||||
|
"filePatterns": [
|
||||||
|
"README.md$",
|
||||||
|
".*\\.md$",
|
||||||
|
"docs/.*",
|
||||||
|
".*\\.py$",
|
||||||
|
".*\\.js$",
|
||||||
|
".*\\.ts$"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
name: OpenHands Documentation
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 2 * * 1' # Weekly on Monday at 2 AM UTC
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches: [ $default-branch ]
|
||||||
|
paths:
|
||||||
|
- 'src/**'
|
||||||
|
- 'lib/**'
|
||||||
|
- '*.py'
|
||||||
|
- '*.js'
|
||||||
|
- '*.ts'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
openhands-docs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install OpenHands API helper
|
||||||
|
run: |
|
||||||
|
curl -O https://raw.githubusercontent.com/All-Hands-AI/OpenHands/main/scripts/openhands_api.py
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install requests
|
||||||
|
|
||||||
|
- name: Generate Documentation with OpenHands
|
||||||
|
env:
|
||||||
|
OPENHANDS_API_KEY: ${{ secrets.OPENHANDS_API_KEY }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
python -c "
|
||||||
|
import sys
|
||||||
|
sys.path.append('.')
|
||||||
|
from openhands_api import OpenHandsAPI
|
||||||
|
|
||||||
|
# Create documentation prompt
|
||||||
|
prompt = '''Please review the current codebase and update the project documentation:
|
||||||
|
|
||||||
|
Repository: ${{ github.repository }}
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
1. Review the README.md and ensure it accurately reflects the current project state
|
||||||
|
2. Update API documentation if there are new endpoints or changes
|
||||||
|
3. Check that code examples in documentation are up-to-date
|
||||||
|
4. Add documentation for any new features or significant changes
|
||||||
|
5. Ensure installation and setup instructions are current
|
||||||
|
6. Update any outdated links or references
|
||||||
|
7. Add or improve code comments where needed
|
||||||
|
|
||||||
|
Please create a pull request with your documentation updates if changes are needed.
|
||||||
|
Focus on clarity, accuracy, and completeness.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Start OpenHands conversation
|
||||||
|
client = OpenHandsAPI()
|
||||||
|
response = client.create_conversation(
|
||||||
|
initial_user_msg=prompt,
|
||||||
|
repository='${{ github.repository }}'
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f'Started OpenHands documentation update: {response.get(\"conversation_id\", \"Unknown\")}')
|
||||||
|
|
||||||
|
# Poll for completion (optional - remove if you want fire-and-forget)
|
||||||
|
try:
|
||||||
|
final_response = client.poll_until_stopped(response['conversation_id'], timeout=900)
|
||||||
|
print(f'Documentation update completed with status: {final_response.get(\"status\", \"Unknown\")}')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Documentation update may still be running: {e}')
|
||||||
|
"
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
"""OpenHands API Python helper for automation tasks.
|
||||||
|
|
||||||
|
Default base_url is https://app.all-hands.dev.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class OpenHandsAPI:
|
||||||
|
"""Minimal client for interacting with the OpenHands API."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
api_key: str | None = None,
|
||||||
|
base_url: str = 'https://app.all-hands.dev',
|
||||||
|
):
|
||||||
|
"""Initialize the API client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api_key: OpenHands API key. If not provided, will use OPENHANDS_API_KEY env var.
|
||||||
|
base_url: Base URL for the OpenHands API. Defaults to https://app.all-hands.dev.
|
||||||
|
"""
|
||||||
|
self.api_key = api_key or os.getenv('OPENHANDS_API_KEY')
|
||||||
|
if not self.api_key:
|
||||||
|
raise ValueError(
|
||||||
|
'API key is required. Set OPENHANDS_API_KEY environment variable or pass api_key parameter.'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.base_url = base_url.rstrip('/')
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update(
|
||||||
|
{
|
||||||
|
'Authorization': f'Bearer {self.api_key}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_conversation(
|
||||||
|
self,
|
||||||
|
initial_user_msg: str,
|
||||||
|
repository: str | None = None,
|
||||||
|
selected_branch: str | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Create a new conversation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
initial_user_msg: The initial message to start the conversation
|
||||||
|
repository: Git repository name in format "owner/repo" (optional)
|
||||||
|
selected_branch: Git branch to use (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Response containing conversation_id and status
|
||||||
|
"""
|
||||||
|
conversation_data: dict[str, Any] = {'initial_user_msg': initial_user_msg}
|
||||||
|
if repository:
|
||||||
|
conversation_data['repository'] = repository
|
||||||
|
if selected_branch:
|
||||||
|
conversation_data['selected_branch'] = selected_branch
|
||||||
|
|
||||||
|
response = self.session.post(
|
||||||
|
f'{self.base_url}/api/conversations', json=conversation_data
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get_conversation(self, conversation_id: str) -> dict[str, Any]:
|
||||||
|
"""Get conversation status and details."""
|
||||||
|
response = self.session.get(
|
||||||
|
f'{self.base_url}/api/conversations/{conversation_id}'
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get_trajectory(self, conversation_id: str) -> dict[str, Any]:
|
||||||
|
"""Get the trajectory (event history) for a conversation."""
|
||||||
|
response = self.session.get(
|
||||||
|
f'{self.base_url}/api/conversations/{conversation_id}/trajectory'
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def poll_until_stopped(
|
||||||
|
self, conversation_id: str, timeout: int = 1200, poll_interval: int = 30
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Poll conversation until it stops or times out."""
|
||||||
|
start = time.time()
|
||||||
|
while time.time() - start < timeout:
|
||||||
|
convo = self.get_conversation(conversation_id)
|
||||||
|
status = str(convo.get('status', '')).upper()
|
||||||
|
if status == 'STOPPED':
|
||||||
|
return convo
|
||||||
|
if status in ['FAILED', 'ERROR', 'CANCELLED']:
|
||||||
|
return convo
|
||||||
|
time.sleep(poll_interval)
|
||||||
|
raise TimeoutError(
|
||||||
|
f'Conversation {conversation_id} did not stop within {timeout} seconds'
|
||||||
|
)
|
||||||
|
|
||||||
|
def post_github_comment(
|
||||||
|
self, repo: str, issue_number: int, comment: str, token: str
|
||||||
|
) -> None:
|
||||||
|
"""Post a comment to a GitHub issue/PR."""
|
||||||
|
url = f'https://api.github.com/repos/{repo}/issues/{issue_number}/comments'
|
||||||
|
headers = {
|
||||||
|
'Authorization': f'token {token}',
|
||||||
|
'Accept': 'application/vnd.github.v3+json',
|
||||||
|
}
|
||||||
|
data = {'body': comment}
|
||||||
|
response = requests.post(url, headers=headers, json=data)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print('OpenHands API helper - import this module to use the OpenHandsAPI class')
|
||||||
Reference in New Issue
Block a user