Skip to content

Commit

Permalink
refactor: restructure microagents system (#5886)
Browse files Browse the repository at this point in the history
Co-authored-by: openhands <[email protected]>
Co-authored-by: Graham Neubig <[email protected]>
  • Loading branch information
3 people authored Jan 2, 2025
1 parent 8983d71 commit c1b514e
Show file tree
Hide file tree
Showing 24 changed files with 776 additions and 147 deletions.
3 changes: 2 additions & 1 deletion .openhands/microagents/repo.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: repo
agent: CodeAct
type: repo
agent: CodeActAgent
---
This repository contains the code for OpenHands, an automated AI software engineer. It has a Python backend
(in the `openhands` directory) and React frontend (in the `frontend` directory).
Expand Down
1 change: 1 addition & 0 deletions containers/app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ ENV VIRTUAL_ENV=/app/.venv \
COPY --chown=openhands:app --chmod=770 --from=backend-builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}
RUN playwright install --with-deps chromium

COPY --chown=openhands:app --chmod=770 ./microagents ./microagents
COPY --chown=openhands:app --chmod=770 ./openhands ./openhands
COPY --chown=openhands:app --chmod=777 ./openhands/runtime/plugins ./openhands/runtime/plugins
COPY --chown=openhands:app --chmod=770 ./openhands/agenthub ./openhands/agenthub
Expand Down
163 changes: 163 additions & 0 deletions microagents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# OpenHands MicroAgents

MicroAgents are specialized prompts that enhance OpenHands with domain-specific knowledge and task-specific workflows. They help developers by providing expert guidance, automating common tasks, and ensuring consistent practices across projects. Each microagent is designed to excel in a specific area, from Git operations to code review processes.

## Sources of Microagents

OpenHands loads microagents from two sources:

### 1. Shareable Microagents (Public)
This directory (`OpenHands/microagents/`) contains shareable microagents that are:
- Available to all OpenHands users
- Maintained in the OpenHands repository
- Perfect for reusable knowledge and common workflows

Directory structure:
```
OpenHands/microagents/
├── knowledge/ # Keyword-triggered expertise
│ ├── git.md # Git operations
│ ├── testing.md # Testing practices
│ └── docker.md # Docker guidelines
└── tasks/ # Interactive workflows
├── pr_review.md # PR review process
├── bug_fix.md # Bug fixing workflow
└── feature.md # Feature implementation
```

### 2. Repository Instructions (Private)
Each repository can have its own instructions in `.openhands/microagents/repo.md`. These instructions are:
- Private to that repository
- Automatically loaded when working with that repository
- Perfect for repository-specific guidelines and team practices

Example repository structure:
```
your-repository/
└── .openhands/
└── microagents/
└── repo.md # Repository-specific instructions
└── knowledges/ # Private micro-agents that are only available inside this repo
└── tasks/ # Private micro-agents that are only available inside this repo
```


## Loading Order

When OpenHands works with a repository, it:
1. Loads repository-specific instructions from `.openhands/microagents/repo.md` if present
2. Loads relevant knowledge agents based on keywords in conversations
3. Enable task agent if user select one of them

## Types of MicroAgents

All microagents use markdown files with YAML frontmatter.


### 1. Knowledge Agents

Knowledge agents provide specialized expertise that's triggered by keywords in conversations. They help with:
- Language best practices
- Framework guidelines
- Common patterns
- Tool usage

Key characteristics:
- **Trigger-based**: Activated by specific keywords in conversations
- **Context-aware**: Provide relevant advice based on file types and content
- **Reusable**: Knowledge can be applied across multiple projects
- **Versioned**: Support multiple versions of tools/frameworks

You can see an example of a knowledge-based agent in [OpenHands's github microagent](https://github.com/All-Hands-AI/OpenHands/tree/main/microagents/knowledge/github.md).

### 2. Repository Agents

Repository agents provide repository-specific knowledge and guidelines. They are:
- Loaded from `.openhands/microagents/repo.md`
- Specific to individual repositories
- Automatically activated for their repository
- Perfect for team practices and project conventions

Key features:
- **Project-specific**: Contains guidelines unique to the repository
- **Team-focused**: Enforces team conventions and practices
- **Always active**: Automatically loaded for the repository
- **Locally maintained**: Updated with the project

You can see an example of a repo agent in [the agent for the OpenHands repo itself](https://github.com/All-Hands-AI/OpenHands/blob/main/.openhands/microagents/repo.md).

### 3. Task Agents

Task agents provide interactive workflows that guide users through common development tasks. They:
- Accept user inputs
- Follow predefined steps
- Adapt to context
- Provide consistent results

Key capabilities:
- **Interactive**: Guide users through complex processes
- **Validating**: Check inputs and conditions
- **Flexible**: Adapt to different scenarios
- **Reproducible**: Ensure consistent outcomes

Example workflow:
You can see an example of a task-based agent in [OpenHands's pull request updating microagent](https://github.com/All-Hands-AI/OpenHands/tree/main/microagents/tasks/update_pr_description.md).

## Contributing

### When to Contribute

1. **Knowledge Agents** - When you have:
- Language/framework best practices
- Tool usage patterns
- Common problem solutions
- General development guidelines

2. **Task Agents** - When you have:
- Repeatable workflows
- Multi-step processes
- Common development tasks
- Standard procedures

3. **Repository Agents** - When you need:
- Project-specific guidelines
- Team conventions and practices
- Custom workflow documentation
- Repository-specific setup instructions

### Best Practices

1. **For Knowledge Agents**:
- Choose distinctive triggers
- Focus on one area of expertise
- Include practical examples
- Use file patterns when relevant
- Keep knowledge general and reusable

2. **For Task Agents**:
- Break workflows into clear steps
- Validate user inputs
- Provide helpful defaults
- Include usage examples
- Make steps adaptable

3. **For Repository Agents**:
- Document clear setup instructions
- Include repository structure details
- Specify testing and build procedures
- List environment requirements
- Maintain up-to-date team practices

### Submission Process

1. Create your agent file in the appropriate directory:
- `knowledge/` for expertise (public, shareable)
- `tasks/` for workflows (public, shareable)
- Note: Repository agents should remain in their respective repositories' `.openhands/microagents/` directory
2. Test thoroughly
3. Submit a pull request to OpenHands


## License

All microagents are subject to the same license as OpenHands. See the root LICENSE file for details.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
name: flarglebargle
type: knowledge
version: 1.0.0
agent: CodeActAgent
triggers:
- flarglebargle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
name: github
type: knowledge
version: 1.0.0
agent: CodeActAgent
triggers:
- github
Expand All @@ -26,4 +28,3 @@ git checkout -b create-widget && git add . && git commit -m "Create widget" && g
curl -X POST "https://api.github.com/repos/$ORG_NAME/$REPO_NAME/pulls" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-d '{"title":"Create widget","head":"create-widget","base":"openhands-workspace"}'
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
name: npm
type: knowledge
version: 1.0.0
agent: CodeActAgent
triggers:
- npm
Expand Down
20 changes: 20 additions & 0 deletions microagents/tasks/address_pr_comments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: address_pr_comments
type: task
version: 1.0.0
author: openhands
agent: CodeActAgent
inputs:
- name: PR_URL
description: "URL of the pull request"
required: true
- name: BRANCH_NAME
description: "Branch name corresponds to the pull request"
required: true
---

First, check the branch {{ BRANCH_NAME }} and read the diff against the main branch to understand the purpose.

This branch corresponds to this PR {{ PR_URL }}

Next, you should use the GitHub API to read the reviews and comments on this PR and address them.
28 changes: 28 additions & 0 deletions microagents/tasks/get_test_to_pass.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: get_test_to_pass
type: task
version: 1.0.0
author: openhands
agent: CodeActAgent
inputs:
- name: BRANCH_NAME
description: "Branch for the agent to work on"
required: true
- name: TEST_COMMAND_TO_RUN
description: "The test command you want the agent to work on. For example, `pytest tests/unit/test_bash_parsing.py`"
required: true
- name: FUNCTION_TO_FIX
description: "The name of function to fix"
required: false
- name: FILE_FOR_FUNCTION
description: "The path of the file that contains the function"
required: false
---

Can you check out branch "{{ BRANCH_NAME }}", and run {{ TEST_COMMAND_TO_RUN }}.

{%- if FUNCTION_TO_FIX and FILE_FOR_FUNCTION %}
Help me fix these tests to pass by fixing the {{ FUNCTION_TO_FIX }} function in file {{ FILE_FOR_FUNCTION }}.
{%- endif %}

PLEASE DO NOT modify the tests by yourselves -- Let me know if you think some of the tests are incorrect.
22 changes: 22 additions & 0 deletions microagents/tasks/update_pr_description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: update_pr_description
type: task
version: 1.0.0
author: openhands
agent: CodeActAgent
inputs:
- name: PR_URL
description: "URL of the pull request"
type: string
required: true
validation:
pattern: "^https://github.com/.+/.+/pull/[0-9]+$"
- name: BRANCH_NAME
description: "Branch name corresponds to the pull request"
type: string
required: true
---

Please check the branch "{{ BRANCH_NAME }}" and look at the diff against the main branch. This branch belongs to this PR "{{ PR_URL }}".

Once you understand the purpose of the diff, please use Github API to read the existing PR description, and update it to be more reflective of the changes we've made when necessary.
22 changes: 22 additions & 0 deletions microagents/tasks/update_test_for_new_implementation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: update_test_for_new_implementation
type: task
version: 1.0.0
author: openhands
agent: CodeActAgent
inputs:
- name: BRANCH_NAME
description: "Branch for the agent to work on"
required: true
- name: TEST_COMMAND_TO_RUN
description: "The test command you want the agent to work on. For example, `pytest tests/unit/test_bash_parsing.py`"
required: true
---

Can you check out branch "{{ BRANCH_NAME }}", and run {{ TEST_COMMAND_TO_RUN }}.

{%- if FUNCTION_TO_FIX and FILE_FOR_FUNCTION %}
Help me fix these tests to pass by fixing the {{ FUNCTION_TO_FIX }} function in file {{ FILE_FOR_FUNCTION }}.
{%- endif %}

PLEASE DO NOT modify the tests by yourselves -- Let me know if you think some of the tests are incorrect.
6 changes: 5 additions & 1 deletion openhands/agenthub/codeact_agent/codeact_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from litellm import ModelResponse

import openhands
import openhands.agenthub.codeact_agent.function_calling as codeact_function_calling
from openhands.controller.agent import Agent
from openhands.controller.state.state import State
Expand Down Expand Up @@ -104,7 +105,10 @@ def __init__(
f'TOOLS loaded for CodeActAgent: {json.dumps(self.tools, indent=2, ensure_ascii=False).replace("\\n", "\n")}'
)
self.prompt_manager = PromptManager(
microagent_dir=os.path.join(os.path.dirname(__file__), 'micro')
microagent_dir=os.path.join(
os.path.dirname(os.path.dirname(openhands.__file__)),
'microagents',
)
if self.config.use_microagents
else None,
prompt_dir=os.path.join(os.path.dirname(__file__), 'prompts'),
Expand Down
6 changes: 4 additions & 2 deletions openhands/controller/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
)
from openhands.llm.llm import LLM
from openhands.runtime.plugins import PluginRequirement
from openhands.utils.prompt import PromptManager

if TYPE_CHECKING:
from openhands.utils.prompt import PromptManager


class Agent(ABC):
Expand All @@ -34,7 +36,7 @@ def __init__(
self.llm = llm
self.config = config
self._complete = False
self.prompt_manager: PromptManager | None = None
self.prompt_manager: 'PromptManager' | None = None

@property
def complete(self) -> bool:
Expand Down
23 changes: 18 additions & 5 deletions openhands/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,6 @@ def __init__(self, message='User cancelled the request'):
super().__init__(message)


class MicroAgentValidationError(Exception):
def __init__(self, message='Micro agent validation failed'):
super().__init__(message)


class OperationCancelled(Exception):
"""Exception raised when an operation is cancelled (e.g. by a keyboard interrupt)."""

Expand Down Expand Up @@ -204,3 +199,21 @@ def __init__(
message='Browser environment is not available, please check if has been initialized',
):
super().__init__(message)


# ============================================
# Microagent Exceptions
# ============================================


class MicroAgentError(Exception):
"""Base exception for all microagent errors."""

pass


class MicroAgentValidationError(MicroAgentError):
"""Raised when there's a validation error in microagent metadata."""

def __init__(self, message='Micro agent validation failed'):
super().__init__(message)
19 changes: 19 additions & 0 deletions openhands/microagent/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from .microagent import (
BaseMicroAgent,
KnowledgeMicroAgent,
RepoMicroAgent,
TaskMicroAgent,
load_microagents_from_dir,
)
from .types import MicroAgentMetadata, MicroAgentType, TaskInput

__all__ = [
'BaseMicroAgent',
'KnowledgeMicroAgent',
'RepoMicroAgent',
'TaskMicroAgent',
'MicroAgentMetadata',
'MicroAgentType',
'TaskInput',
'load_microagents_from_dir',
]
Loading

0 comments on commit c1b514e

Please sign in to comment.