mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-04-29 03:00:45 -04:00
Compare commits
63 Commits
resolver-r
...
update-mic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93287ef9ac | ||
|
|
e70595f46f | ||
|
|
1d3ff66987 | ||
|
|
1a95f86802 | ||
|
|
eee12bfd94 | ||
|
|
8c2d4dbe8b | ||
|
|
0ca3188afa | ||
|
|
283f503870 | ||
|
|
0691e5c0d0 | ||
|
|
fc16da8fd2 | ||
|
|
bd3ff43c67 | ||
|
|
0fe5b808af | ||
|
|
6c49686ff0 | ||
|
|
17212bb2f2 | ||
|
|
9d9f931e95 | ||
|
|
6fe9680474 | ||
|
|
53c80d1c92 | ||
|
|
401262f353 | ||
|
|
58845b01a3 | ||
|
|
469d184157 | ||
|
|
4837c4dc74 | ||
|
|
6763f21cc3 | ||
|
|
32e610ac1d | ||
|
|
85c65391ca | ||
|
|
c444dbfbbf | ||
|
|
dd988d0f14 | ||
|
|
6f1a74e286 | ||
|
|
7b956b6103 | ||
|
|
34b097115d | ||
|
|
3e4ab4f379 | ||
|
|
54cd9f7e44 | ||
|
|
802b765f98 | ||
|
|
18c88f99ff | ||
|
|
f3934be07b | ||
|
|
6ce9f49d1e | ||
|
|
fc07622b20 | ||
|
|
da935f9d8f | ||
|
|
642cc52a1a | ||
|
|
4c361ab9e5 | ||
|
|
5dfa1bb6eb | ||
|
|
a07cf972a5 | ||
|
|
f2e3bc3254 | ||
|
|
3790ec7d60 | ||
|
|
3c0719309e | ||
|
|
0236e0943e | ||
|
|
cd464c0022 | ||
|
|
4519a7f4f3 | ||
|
|
fdc591330b | ||
|
|
98e454e82c | ||
|
|
e088d2d24a | ||
|
|
58c574af1e | ||
|
|
405f0069f8 | ||
|
|
f26d770d03 | ||
|
|
bf2c3de219 | ||
|
|
7c35ce16e5 | ||
|
|
f4024ccd94 | ||
|
|
b55bfed831 | ||
|
|
cb0994027f | ||
|
|
bcc9bd0b9a | ||
|
|
6c144e6b5a | ||
|
|
e90b841b0d | ||
|
|
a1e6ed4dff | ||
|
|
ad6311d3cd |
@@ -5,26 +5,111 @@ description: Keyword-triggered microagents provide OpenHands with specific instr
|
||||
|
||||
## Usage
|
||||
|
||||
These microagents are only loaded when a prompt includes one of the trigger words.
|
||||
Keyword-triggered microagents are only loaded when a prompt includes one of the trigger words. There are two types of keyword-triggered microagents:
|
||||
|
||||
1. **Standard Keyword Microagents**: Triggered by keywords embedded in text
|
||||
2. **Command-Style Microagents**: Triggered by command-style inputs (e.g., `/fix_test`) that can prompt for user input
|
||||
|
||||
Additionally, there's a special type of microagent that's always active:
|
||||
|
||||
3. **Repository Microagents**: Always active for a specific repository, providing repository-specific context and tools
|
||||
|
||||
## Frontmatter Syntax
|
||||
|
||||
Frontmatter is required for keyword-triggered microagents. It must be placed at the top of the file,
|
||||
above the guidelines.
|
||||
above the guidelines. Enclose the frontmatter in triple dashes (---).
|
||||
|
||||
Enclose the frontmatter in triple dashes (---) and include the following fields:
|
||||
### Standard Keyword Microagents
|
||||
|
||||
For standard keyword microagents, include the following fields:
|
||||
|
||||
| Field | Description | Required | Default |
|
||||
|------------|--------------------------------------------------|----------|------------------|
|
||||
| `name` | The name of the microagent | No | Filename |
|
||||
| `type` | The type of microagent (`knowledge`) | No | Inferred |
|
||||
| `triggers` | A list of keywords that activate the microagent. | Yes | None |
|
||||
| `agent` | The agent this microagent applies to. | No | 'CodeActAgent' |
|
||||
|
||||
### Command-Style Microagents
|
||||
|
||||
## Example
|
||||
For command-style microagents that require user input, include the following fields:
|
||||
|
||||
Keyword-triggered microagent file example located at `.openhands/microagents/yummy.md`:
|
||||
```
|
||||
| Field | Description | Required | Default |
|
||||
|------------|------------------------------------------------------------|----------|------------------|
|
||||
| `name` | The name of the microagent | No | Filename |
|
||||
| `type` | The type of microagent (`task`) | No | Inferred |
|
||||
| `triggers` | A list of command triggers (e.g., `/fix_test`) | No | `/[name]` |
|
||||
| `inputs` | A list of input variables the microagent requires | Yes | None |
|
||||
|
||||
### Repository Microagents
|
||||
|
||||
Repository microagents are always active for a specific repository. They provide repository-specific context and tools.
|
||||
|
||||
| Field | Description | Required | Default |
|
||||
|------------|------------------------------------------------------------|----------|------------------|
|
||||
| `name` | The name of the microagent | No | Filename |
|
||||
| `type` | The type of microagent (`repo`) | No | Inferred |
|
||||
|
||||
#### Repository Microagent Example
|
||||
|
||||
Here's an example of a repository microagent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
# The type field is optional and will be inferred as 'repo' when no triggers are present
|
||||
---
|
||||
|
||||
# Repository Guidelines
|
||||
|
||||
This repository follows these coding standards:
|
||||
1. Use PEP 8 for Python code
|
||||
2. Use ESLint for JavaScript code
|
||||
3. Write unit tests for all new features
|
||||
```
|
||||
|
||||
This microagent is always active when working with the repository and provides repository-specific guidelines.
|
||||
|
||||
### MCP Tools Support
|
||||
|
||||
Microagents can also provide additional MCP (Model-Code-Prompt) tools to the agent. This is useful for extending the agent's capabilities with custom tools.
|
||||
|
||||
| Field | Description | Required | Default |
|
||||
|--------------|-----------------------------------------------------------|----------|------------------|
|
||||
| `mcp_tools` | Configuration for additional MCP tools | No | None |
|
||||
|
||||
#### MCP Tools Example
|
||||
|
||||
Here's an example of a microagent that provides an additional MCP tool (the `fetch` tool for accessing web content):
|
||||
|
||||
```yaml
|
||||
---
|
||||
# The type field is optional and will be inferred as 'repo' when no triggers are present
|
||||
mcp_tools:
|
||||
stdio_servers:
|
||||
- name: "fetch"
|
||||
command: uvx
|
||||
args:
|
||||
- mcp-server-fetch
|
||||
---
|
||||
```
|
||||
|
||||
This microagent is a repository microagent (always active) that adds the `fetch` tool to the agent's capabilities.
|
||||
|
||||
Each input in the `inputs` list requires:
|
||||
|
||||
| Field | Description | Required |
|
||||
|---------------|--------------------------------------------------|----------|
|
||||
| `name` | The name of the input variable | Yes |
|
||||
| `description` | A description of what the input should contain | Yes |
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
### Standard Keyword Microagent Example
|
||||
|
||||
Standard keyword microagent file example located at `.openhands/microagents/yummy.md`:
|
||||
```yaml
|
||||
---
|
||||
# The type field is optional and will be inferred as 'knowledge' when triggers are present
|
||||
triggers:
|
||||
- yummyhappy
|
||||
- happyyummy
|
||||
@@ -33,4 +118,58 @@ triggers:
|
||||
The user has said the magic word. Respond with "That was delicious!"
|
||||
```
|
||||
|
||||
[See examples of microagents triggered by keywords in the official OpenHands repository](https://github.com/All-Hands-AI/OpenHands/tree/main/microagents)
|
||||
### Command-Style Microagent Example
|
||||
|
||||
Command-style microagent file example located at `.openhands/microagents/fix_test.md`:
|
||||
```yaml
|
||||
---
|
||||
# The type field is optional and will be inferred as 'task' when inputs are present
|
||||
triggers:
|
||||
- /fix_test
|
||||
inputs:
|
||||
- name: BRANCH_NAME
|
||||
description: "Branch for the agent to work on"
|
||||
- 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`"
|
||||
- name: FUNCTION_TO_FIX
|
||||
description: "The name of function to fix"
|
||||
- name: FILE_FOR_FUNCTION
|
||||
description: "The path of the file that contains the function"
|
||||
---
|
||||
|
||||
Can you check out branch "{{ BRANCH_NAME }}", and run {{ TEST_COMMAND_TO_RUN }}.
|
||||
|
||||
Help me fix these tests to pass by fixing the {{ FUNCTION_TO_FIX }} function in file {{ FILE_FOR_FUNCTION }}.
|
||||
|
||||
PLEASE DO NOT modify the tests by yourself -- Let me know if you think some of the tests are incorrect.
|
||||
```
|
||||
|
||||
## Using Command-Style Microagents
|
||||
|
||||
Command-style microagents are designed to streamline common development tasks by providing structured templates for specific operations. They are triggered using a command-style format and will prompt the user for any required inputs.
|
||||
|
||||
### How to Use
|
||||
|
||||
1. Type `/` in the chat input to see available command-style microagents
|
||||
2. Select a microagent from the dropdown or type its name (e.g., `/fix_test`)
|
||||
3. The agent will prompt you for any required inputs
|
||||
4. Provide the requested information
|
||||
5. The agent will execute the task with your inputs
|
||||
|
||||
### Template Variables
|
||||
|
||||
In the body of a command-style microagent, you can reference input variables using the `{{ VARIABLE_NAME }}` syntax. These will be replaced with the user-provided values when the microagent is triggered.
|
||||
|
||||
### Available Command-Style Microagents
|
||||
|
||||
OpenHands includes several built-in command-style microagents:
|
||||
|
||||
| Command | Description |
|
||||
|----------------------|-------------------------------------------------------|
|
||||
| `/fix_test` | Fix failing tests by modifying a specific function |
|
||||
| `/update_test` | Update tests for a new implementation |
|
||||
| `/update_pr` | Update a pull request description |
|
||||
| `/address_pr_comments` | Address comments on a pull request |
|
||||
| `/add_repo_instruction` | Add instructions to the repository microagent |
|
||||
|
||||
[See examples of microagents in the official OpenHands repository](https://github.com/All-Hands-AI/OpenHands/tree/main/microagents)
|
||||
|
||||
@@ -8,7 +8,7 @@ description: Microagents are specialized prompts that enhance OpenHands with dom
|
||||
Currently OpenHands supports the following types of microagents:
|
||||
|
||||
- [General Microagents](./microagents-repo): General guidelines for OpenHands about the repository.
|
||||
- [Keyword-Triggered Microagents](./microagents-keyword): Guidelines activated by specific keywords in prompts.
|
||||
- [Keyword-Triggered Microagents](./microagents-keyword): Guidelines activated by specific keywords in prompts, including command-style microagents that prompt for user inputs.
|
||||
|
||||
To customize OpenHands' behavior, create a .openhands/microagents/ directory in the root of your repository and
|
||||
add `<microagent_name>.md` files inside. For repository-specific guidelines, you can ask OpenHands to analyze your repository and create a comprehensive `repo.md` file (see [General Microagents](./microagents-repo) for details).
|
||||
@@ -34,7 +34,7 @@ some-repository/
|
||||
Each microagent file may include frontmatter that provides additional information. In some cases, this frontmatter
|
||||
is required:
|
||||
|
||||
| Microagent Type | Required |
|
||||
|---------------------------------|----------|
|
||||
| `General Microagents` | No |
|
||||
| `Keyword-Triggered Microagents` | Yes |
|
||||
| Microagent Type | Required |
|
||||
|------------------------------------------------|----------|
|
||||
| `General Microagents` | No |
|
||||
| `Keyword-Triggered Microagents (all types)` | Yes |
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
---
|
||||
name: add_agent
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- new agent
|
||||
- new microagent
|
||||
- create agent
|
||||
- create an agent
|
||||
- create microagent
|
||||
- create a microagent
|
||||
- add agent
|
||||
- add an agent
|
||||
- add microagent
|
||||
- add a microagent
|
||||
- microagent template
|
||||
- new agent
|
||||
- new microagent
|
||||
- create agent
|
||||
- create an agent
|
||||
- create microagent
|
||||
- create a microagent
|
||||
- add agent
|
||||
- add an agent
|
||||
- add microagent
|
||||
- add a microagent
|
||||
- microagent template
|
||||
---
|
||||
|
||||
This agent helps create new microagents in the `.openhands/microagents` directory by providing guidance and templates.
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
---
|
||||
name: add_repo_inst
|
||||
version: 1.0.0
|
||||
author: openhands
|
||||
agent: CodeActAgent
|
||||
inputs:
|
||||
- description: Branch for the agent to work on
|
||||
name: REPO_FOLDER_NAME
|
||||
triggers:
|
||||
- /add_repo_inst
|
||||
inputs:
|
||||
- name: REPO_FOLDER_NAME
|
||||
description: "Branch for the agent to work on"
|
||||
---
|
||||
|
||||
Please browse the current repository under /workspace/{{ REPO_FOLDER_NAME }}, look at the documentation and relevant code, and understand the purpose of this repository.
|
||||
@@ -18,7 +14,6 @@ Here's an example:
|
||||
```markdown
|
||||
---
|
||||
name: repo
|
||||
type: repo
|
||||
agent: CodeActAgent
|
||||
---
|
||||
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
---
|
||||
name: address_pr_comments
|
||||
version: 1.0.0
|
||||
author: openhands
|
||||
agent: CodeActAgent
|
||||
inputs:
|
||||
- description: URL of the pull request
|
||||
name: PR_URL
|
||||
- description: Branch name corresponds to the pull request
|
||||
name: BRANCH_NAME
|
||||
triggers:
|
||||
- /address_pr_comments
|
||||
inputs:
|
||||
- name: PR_URL
|
||||
description: "URL of the pull request"
|
||||
- name: BRANCH_NAME
|
||||
description: "Branch name corresponds to the pull request"
|
||||
---
|
||||
|
||||
First, check the branch {{ BRANCH_NAME }} and read the diff against the main branch to understand the purpose.
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
name: agent_memory
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- /remember
|
||||
---
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
---
|
||||
# This is a repo microagent that is always activated
|
||||
# to include necessary default tools implemented with MCP
|
||||
name: default-tools
|
||||
type: repo
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
mcp_tools:
|
||||
stdio_servers:
|
||||
- name: "fetch"
|
||||
command: "uvx"
|
||||
args: ["mcp-server-fetch"]
|
||||
# We leave the body empty because MCP tools will automatically add the
|
||||
# tool description for LLMs in tool calls, so there's no need to add extra descriptions.
|
||||
- args:
|
||||
- mcp-server-fetch
|
||||
command: uvx
|
||||
name: fetch
|
||||
---
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
name: docker
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- docker
|
||||
- container
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
---
|
||||
name: fix_test
|
||||
version: 1.0.0
|
||||
author: openhands
|
||||
agent: CodeActAgent
|
||||
inputs:
|
||||
- description: Branch for the agent to work on
|
||||
name: BRANCH_NAME
|
||||
- description: The test command you want the agent to work on. For example, `pytest
|
||||
tests/unit/test_bash_parsing.py`
|
||||
name: TEST_COMMAND_TO_RUN
|
||||
- description: The name of function to fix
|
||||
name: FUNCTION_TO_FIX
|
||||
- description: The path of the file that contains the function
|
||||
name: FILE_FOR_FUNCTION
|
||||
triggers:
|
||||
- /fix_test
|
||||
inputs:
|
||||
- name: BRANCH_NAME
|
||||
description: "Branch for the agent to work on"
|
||||
- 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`"
|
||||
- name: FUNCTION_TO_FIX
|
||||
description: "The name of function to fix"
|
||||
- name: FILE_FOR_FUNCTION
|
||||
description: "The path of the file that contains the function"
|
||||
---
|
||||
|
||||
Can you check out branch "{{ BRANCH_NAME }}", and run {{ TEST_COMMAND_TO_RUN }}.
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
name: flarglebargle
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- flarglebargle
|
||||
---
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
name: github
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- github
|
||||
- git
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
name: gitlab
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- gitlab
|
||||
- git
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
name: kubernetes
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- kubernetes
|
||||
- k8s
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
name: npm
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- npm
|
||||
---
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
name: pdflatex
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- pdflatex
|
||||
---
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
---
|
||||
name: security
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- security
|
||||
- vulnerability
|
||||
- authentication
|
||||
- authorization
|
||||
- permissions
|
||||
- security
|
||||
- vulnerability
|
||||
- authentication
|
||||
- authorization
|
||||
- permissions
|
||||
---
|
||||
|
||||
This document provides guidance on security best practices
|
||||
|
||||
You should always be considering security implications when developing.
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
---
|
||||
name: SSH Microagent
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- ssh
|
||||
- remote server
|
||||
- remote machine
|
||||
- remote host
|
||||
- remote connection
|
||||
- secure shell
|
||||
- ssh keys
|
||||
- ssh
|
||||
- remote server
|
||||
- remote machine
|
||||
- remote host
|
||||
- remote connection
|
||||
- secure shell
|
||||
- ssh keys
|
||||
---
|
||||
|
||||
# SSH Microagent
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
---
|
||||
name: swift-linux
|
||||
type: knowledge
|
||||
agent: CodeActAgent
|
||||
version: 1.0.0
|
||||
triggers:
|
||||
- swift-linux
|
||||
- swift-debian
|
||||
- swift-installation
|
||||
triggers:
|
||||
- swift-linux
|
||||
- swift-debian
|
||||
- swift-installation
|
||||
---
|
||||
|
||||
# Swift Installation Guide for Debian Linux
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
---
|
||||
name: update_pr_description
|
||||
version: 1.0.0
|
||||
author: openhands
|
||||
agent: CodeActAgent
|
||||
inputs:
|
||||
- description: URL of the pull request
|
||||
name: PR_URL
|
||||
type: string
|
||||
validation:
|
||||
pattern: ^https://github.com/.+/.+/pull/[0-9]+$
|
||||
- description: Branch name corresponds to the pull request
|
||||
name: BRANCH_NAME
|
||||
type: string
|
||||
triggers:
|
||||
- /update_pr_description
|
||||
inputs:
|
||||
- name: PR_URL
|
||||
description: "URL of the pull request"
|
||||
type: string
|
||||
validation:
|
||||
pattern: "^https://github.com/.+/.+/pull/[0-9]+$"
|
||||
- name: BRANCH_NAME
|
||||
description: "Branch name corresponds to the pull request"
|
||||
type: string
|
||||
---
|
||||
|
||||
Please check the branch "{{ BRANCH_NAME }}" and look at the diff against the main branch. This branch belongs to this PR "{{ PR_URL }}".
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
---
|
||||
name: update_test
|
||||
version: 1.0.0
|
||||
author: openhands
|
||||
agent: CodeActAgent
|
||||
inputs:
|
||||
- description: Branch for the agent to work on
|
||||
name: BRANCH_NAME
|
||||
- description: The test command you want the agent to work on. For example, `pytest
|
||||
tests/unit/test_bash_parsing.py`
|
||||
name: TEST_COMMAND_TO_RUN
|
||||
triggers:
|
||||
- /update_test
|
||||
inputs:
|
||||
- name: BRANCH_NAME
|
||||
description: "Branch for the agent to work on"
|
||||
- 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`"
|
||||
---
|
||||
|
||||
Can you check out branch "{{ BRANCH_NAME }}", and run {{ TEST_COMMAND_TO_RUN }}.
|
||||
|
||||
@@ -40,6 +40,11 @@ class BaseMicroagent(BaseModel):
|
||||
derived_name = None
|
||||
if microagent_dir is not None:
|
||||
derived_name = str(path.relative_to(microagent_dir).with_suffix(''))
|
||||
else:
|
||||
derived_name = path.with_suffix('').name
|
||||
logger.warning(
|
||||
f'No microagent_dir provided. Microagent name will be the file name: {derived_name}'
|
||||
)
|
||||
|
||||
# Only load directly from path if file_content is not provided
|
||||
if file_content is None:
|
||||
@@ -95,6 +100,16 @@ class BaseMicroagent(BaseModel):
|
||||
MicroagentType.TASK: TaskMicroagent,
|
||||
}
|
||||
|
||||
# We will always use derived_name if available
|
||||
assert derived_name is not None
|
||||
agent_name = derived_name
|
||||
if metadata.name is not None:
|
||||
logger.warning(
|
||||
f'Detected `name:` field in frontmatter for microagent {metadata.name}. '
|
||||
"This is deprecated. Microagent's name will use the file name "
|
||||
f'({derived_name}) instead.'
|
||||
)
|
||||
|
||||
# Infer the agent type:
|
||||
# 1. If inputs exist -> TASK
|
||||
# 2. If triggers exist -> KNOWLEDGE
|
||||
@@ -102,8 +117,7 @@ class BaseMicroagent(BaseModel):
|
||||
inferred_type: MicroagentType
|
||||
if metadata.inputs:
|
||||
inferred_type = MicroagentType.TASK
|
||||
# Add a trigger for the agent name if not already present
|
||||
trigger = f'/{metadata.name}'
|
||||
trigger = f'/{agent_name}'
|
||||
if not metadata.triggers or trigger not in metadata.triggers:
|
||||
if not metadata.triggers:
|
||||
metadata.triggers = [trigger]
|
||||
@@ -120,9 +134,6 @@ class BaseMicroagent(BaseModel):
|
||||
# This should theoretically not happen with the logic above
|
||||
raise ValueError(f'Could not determine microagent type for: {path}')
|
||||
|
||||
# Use derived_name if available (from relative path), otherwise fallback to metadata.name
|
||||
agent_name = derived_name if derived_name is not None else metadata.name
|
||||
|
||||
agent_class = subclass_map[inferred_type]
|
||||
return agent_class(
|
||||
name=agent_name,
|
||||
|
||||
@@ -25,10 +25,12 @@ class InputMetadata(BaseModel):
|
||||
class MicroagentMetadata(BaseModel):
|
||||
"""Metadata for all microagents."""
|
||||
|
||||
name: str = 'default'
|
||||
name: str = Field(default='default', exclude=True)
|
||||
type: MicroagentType = Field(default=MicroagentType.REPO_KNOWLEDGE)
|
||||
version: str = Field(default='1.0.0')
|
||||
agent: str = Field(default='CodeActAgent')
|
||||
# Keep these fields for backward compatibility but they're not used
|
||||
version: str = Field(default='1.0.0', exclude=True)
|
||||
agent: str = Field(default='CodeActAgent', exclude=True)
|
||||
author: str = Field(default='', exclude=True)
|
||||
triggers: list[str] = [] # optional, only exists for knowledge microagents
|
||||
inputs: list[InputMetadata] = [] # optional, only exists for task microagents
|
||||
mcp_tools: MCPConfig | None = (
|
||||
|
||||
19
poetry.lock
generated
19
poetry.lock
generated
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aioboto3"
|
||||
@@ -462,7 +462,7 @@ description = "LTS Port of Python audioop"
|
||||
optional = false
|
||||
python-versions = ">=3.13"
|
||||
groups = ["main"]
|
||||
markers = "python_version >= \"3.13\""
|
||||
markers = "python_version == \"3.13\""
|
||||
files = [
|
||||
{file = "audioop_lts-0.2.1-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd1345ae99e17e6910f47ce7d52673c6a1a70820d78b67de1b7abb3af29c426a"},
|
||||
{file = "audioop_lts-0.2.1-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:e175350da05d2087e12cea8e72a70a1a8b14a17e92ed2022952a4419689ede5e"},
|
||||
@@ -1644,7 +1644,7 @@ files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
markers = {main = "platform_system == \"Windows\" or sys_platform == \"win32\" or os_name == \"nt\"", dev = "os_name == \"nt\" or sys_platform == \"win32\"", runtime = "sys_platform == \"win32\"", test = "platform_system == \"Windows\" or sys_platform == \"win32\""}
|
||||
markers = {main = "platform_system == \"Windows\" or os_name == \"nt\" or sys_platform == \"win32\"", dev = "os_name == \"nt\" or sys_platform == \"win32\"", runtime = "sys_platform == \"win32\"", test = "platform_system == \"Windows\" or sys_platform == \"win32\""}
|
||||
|
||||
[[package]]
|
||||
name = "comm"
|
||||
@@ -3053,8 +3053,8 @@ files = [
|
||||
google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]}
|
||||
google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev"
|
||||
proto-plus = [
|
||||
{version = ">=1.22.3,<2.0.0dev"},
|
||||
{version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""},
|
||||
{version = ">=1.22.3,<2.0.0dev"},
|
||||
]
|
||||
protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev"
|
||||
|
||||
@@ -3076,8 +3076,8 @@ googleapis-common-protos = ">=1.56.2,<2.0.0"
|
||||
grpcio = {version = ">=1.49.1,<2.0.0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}
|
||||
grpcio-status = {version = ">=1.49.1,<2.0.0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}
|
||||
proto-plus = [
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
{version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""},
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
]
|
||||
protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0"
|
||||
requests = ">=2.18.0,<3.0.0"
|
||||
@@ -3295,8 +3295,8 @@ google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0", extras
|
||||
google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0"
|
||||
grpc-google-iam-v1 = ">=0.14.0,<1.0.0"
|
||||
proto-plus = [
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
{version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""},
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
]
|
||||
protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0"
|
||||
|
||||
@@ -6586,8 +6586,8 @@ files = [
|
||||
[package.dependencies]
|
||||
googleapis-common-protos = ">=1.52,<2.0"
|
||||
grpcio = [
|
||||
{version = ">=1.63.2,<2.0.0", markers = "python_version < \"3.13\""},
|
||||
{version = ">=1.66.2,<2.0.0", markers = "python_version >= \"3.13\""},
|
||||
{version = ">=1.63.2,<2.0.0", markers = "python_version < \"3.13\""},
|
||||
]
|
||||
opentelemetry-api = ">=1.15,<2.0"
|
||||
opentelemetry-exporter-otlp-proto-common = "1.34.1"
|
||||
@@ -9350,7 +9350,6 @@ files = [
|
||||
{file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"},
|
||||
{file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"},
|
||||
]
|
||||
markers = {evaluation = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
|
||||
[package.extras]
|
||||
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""]
|
||||
@@ -9593,7 +9592,7 @@ description = "Standard library aifc redistribution. \"dead battery\"."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
markers = "python_version >= \"3.13\""
|
||||
markers = "python_version == \"3.13\""
|
||||
files = [
|
||||
{file = "standard_aifc-3.13.0-py3-none-any.whl", hash = "sha256:f7ae09cc57de1224a0dd8e3eb8f73830be7c3d0bc485de4c1f82b4a7f645ac66"},
|
||||
{file = "standard_aifc-3.13.0.tar.gz", hash = "sha256:64e249c7cb4b3daf2fdba4e95721f811bde8bdfc43ad9f936589b7bb2fae2e43"},
|
||||
@@ -9610,7 +9609,7 @@ description = "Standard library chunk redistribution. \"dead battery\"."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
markers = "python_version >= \"3.13\""
|
||||
markers = "python_version == \"3.13\""
|
||||
files = [
|
||||
{file = "standard_chunk-3.13.0-py3-none-any.whl", hash = "sha256:17880a26c285189c644bd5bd8f8ed2bdb795d216e3293e6dbe55bbd848e2982c"},
|
||||
{file = "standard_chunk-3.13.0.tar.gz", hash = "sha256:4ac345d37d7e686d2755e01836b8d98eda0d1a3ee90375e597ae43aaf064d654"},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""Tests for microagent loading in runtime."""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
@@ -20,7 +19,7 @@ from openhands.microagent.microagent import (
|
||||
RepoMicroagent,
|
||||
TaskMicroagent,
|
||||
)
|
||||
from openhands.microagent.types import MicroagentType
|
||||
from openhands.microagent.types import InputMetadata, MicroagentType
|
||||
|
||||
|
||||
def _create_test_microagents(test_dir: str):
|
||||
@@ -32,10 +31,6 @@ def _create_test_microagents(test_dir: str):
|
||||
knowledge_dir = microagents_dir / 'knowledge'
|
||||
knowledge_dir.mkdir(exist_ok=True)
|
||||
knowledge_agent = """---
|
||||
name: test_knowledge_agent
|
||||
type: knowledge
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
triggers:
|
||||
- test
|
||||
- pytest
|
||||
@@ -45,17 +40,10 @@ triggers:
|
||||
|
||||
Testing best practices and guidelines.
|
||||
"""
|
||||
(knowledge_dir / 'knowledge.md').write_text(knowledge_agent)
|
||||
(knowledge_dir / 'test_knowledge_agent.md').write_text(knowledge_agent)
|
||||
|
||||
# Create test repo agent
|
||||
repo_agent = """---
|
||||
name: test_repo_agent
|
||||
type: repo
|
||||
version: 1.0.0
|
||||
agent: CodeActAgent
|
||||
---
|
||||
|
||||
# Test Repository Agent
|
||||
repo_agent = """# Test Repository Agent
|
||||
|
||||
Repository-specific test instructions.
|
||||
"""
|
||||
@@ -89,7 +77,7 @@ def test_load_microagents_with_trailing_slashes(
|
||||
# Check knowledge agents
|
||||
assert len(knowledge_agents) == 1
|
||||
agent = knowledge_agents[0]
|
||||
assert agent.name == 'knowledge/knowledge'
|
||||
assert agent.name == 'knowledge/test_knowledge_agent'
|
||||
assert 'test' in agent.triggers
|
||||
assert 'pytest' in agent.triggers
|
||||
|
||||
@@ -126,7 +114,7 @@ def test_load_microagents_with_selected_repo(temp_dir, runtime_cls, run_as_openh
|
||||
# Check knowledge agents
|
||||
assert len(knowledge_agents) == 1
|
||||
agent = knowledge_agents[0]
|
||||
assert agent.name == 'knowledge/knowledge'
|
||||
assert agent.name == 'knowledge/test_knowledge_agent'
|
||||
assert 'test' in agent.triggers
|
||||
assert 'pytest' in agent.triggers
|
||||
|
||||
@@ -180,7 +168,7 @@ Repository-specific test instructions.
|
||||
_close_test_runtime(runtime)
|
||||
|
||||
|
||||
def test_task_microagent_creation():
|
||||
def test_task_microagent_creation(temp_dir):
|
||||
"""Test that a TaskMicroagent is created correctly."""
|
||||
content = """---
|
||||
name: test_task
|
||||
@@ -196,21 +184,43 @@ inputs:
|
||||
|
||||
This is a test task microagent with a variable: ${test_var}.
|
||||
"""
|
||||
with open(os.path.join(temp_dir, 'test_task.md'), 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.md') as f:
|
||||
f.write(content.encode())
|
||||
f.flush()
|
||||
agent = BaseMicroagent.load(os.path.join(temp_dir, 'test_task.md'))
|
||||
|
||||
agent = BaseMicroagent.load(f.name)
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
assert agent.type == MicroagentType.TASK
|
||||
assert agent.name == 'test_task'
|
||||
assert '/test_task' in agent.triggers
|
||||
assert "If the user didn't provide any of these variables" in agent.content
|
||||
assert agent.inputs == [InputMetadata(name='TEST_VAR', description='Test variable')]
|
||||
simplified_content = """---
|
||||
triggers:
|
||||
- /test_task
|
||||
inputs:
|
||||
- name: TEST_VAR
|
||||
description: "Test variable"
|
||||
---
|
||||
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
assert agent.type == MicroagentType.TASK
|
||||
assert agent.name == 'test_task'
|
||||
assert '/test_task' in agent.triggers
|
||||
assert "If the user didn't provide any of these variables" in agent.content
|
||||
This is a test task microagent with a variable: ${test_var}.
|
||||
"""
|
||||
|
||||
with open(os.path.join(temp_dir, 'test_task.md'), 'w') as f:
|
||||
f.write(simplified_content)
|
||||
|
||||
simplified_agent = BaseMicroagent.load(os.path.join(temp_dir, 'test_task.md'))
|
||||
|
||||
assert isinstance(simplified_agent, TaskMicroagent)
|
||||
assert simplified_agent.type == MicroagentType.TASK
|
||||
assert simplified_agent.name == 'test_task'
|
||||
assert '/test_task' in simplified_agent.triggers
|
||||
assert (
|
||||
"If the user didn't provide any of these variables" in simplified_agent.content
|
||||
)
|
||||
|
||||
|
||||
def test_task_microagent_variable_extraction():
|
||||
def test_task_microagent_variable_extraction(temp_dir):
|
||||
"""Test that variables are correctly extracted from the content."""
|
||||
content = """---
|
||||
name: test_task
|
||||
@@ -227,19 +237,18 @@ inputs:
|
||||
This is a test with variables: ${var1}, ${var2}, and ${var3}.
|
||||
"""
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.md') as f:
|
||||
f.write(content.encode())
|
||||
f.flush()
|
||||
with open(os.path.join(temp_dir, 'test_task.md'), 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
agent = BaseMicroagent.load(f.name)
|
||||
agent = BaseMicroagent.load(os.path.join(temp_dir, 'test_task.md'))
|
||||
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
variables = agent.extract_variables(agent.content)
|
||||
assert set(variables) == {'var1', 'var2', 'var3'}
|
||||
assert agent.requires_user_input()
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
variables = agent.extract_variables(agent.content)
|
||||
assert set(variables) == {'var1', 'var2', 'var3'}
|
||||
assert agent.requires_user_input()
|
||||
|
||||
|
||||
def test_knowledge_microagent_no_prompt():
|
||||
def test_knowledge_microagent_no_prompt(temp_dir):
|
||||
"""Test that a regular KnowledgeMicroagent doesn't get the prompt."""
|
||||
content = """---
|
||||
name: test_knowledge
|
||||
@@ -252,19 +261,17 @@ triggers:
|
||||
|
||||
This is a test knowledge microagent.
|
||||
"""
|
||||
with open(os.path.join(temp_dir, 'test_knowledge.md'), 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.md') as f:
|
||||
f.write(content.encode())
|
||||
f.flush()
|
||||
agent = BaseMicroagent.load(os.path.join(temp_dir, 'test_knowledge.md'))
|
||||
|
||||
agent = BaseMicroagent.load(f.name)
|
||||
|
||||
assert isinstance(agent, KnowledgeMicroagent)
|
||||
assert agent.type == MicroagentType.KNOWLEDGE
|
||||
assert "If the user didn't provide any of these variables" not in agent.content
|
||||
assert isinstance(agent, KnowledgeMicroagent)
|
||||
assert agent.type == MicroagentType.KNOWLEDGE
|
||||
assert "If the user didn't provide any of these variables" not in agent.content
|
||||
|
||||
|
||||
def test_task_microagent_trigger_addition():
|
||||
def test_task_microagent_trigger_addition(temp_dir):
|
||||
"""Test that a trigger is added if not present."""
|
||||
content = """---
|
||||
name: test_task
|
||||
@@ -278,18 +285,16 @@ inputs:
|
||||
|
||||
This is a test task microagent.
|
||||
"""
|
||||
with open(os.path.join(temp_dir, 'test_task.md'), 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.md') as f:
|
||||
f.write(content.encode())
|
||||
f.flush()
|
||||
agent = BaseMicroagent.load(os.path.join(temp_dir, 'test_task.md'))
|
||||
|
||||
agent = BaseMicroagent.load(f.name)
|
||||
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
assert '/test_task' in agent.triggers
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
assert '/test_task' in agent.triggers
|
||||
|
||||
|
||||
def test_task_microagent_no_duplicate_trigger():
|
||||
def test_task_microagent_no_duplicate_trigger(temp_dir):
|
||||
"""Test that a trigger is not duplicated if already present."""
|
||||
content = """---
|
||||
name: test_task
|
||||
@@ -306,21 +311,19 @@ inputs:
|
||||
|
||||
This is a test task microagent.
|
||||
"""
|
||||
with open(os.path.join(temp_dir, 'test_task.md'), 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.md') as f:
|
||||
f.write(content.encode())
|
||||
f.flush()
|
||||
agent = BaseMicroagent.load(os.path.join(temp_dir, 'test_task.md'))
|
||||
|
||||
agent = BaseMicroagent.load(f.name)
|
||||
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
assert agent.triggers.count('/test_task') == 1 # No duplicates
|
||||
assert len(agent.triggers) == 2
|
||||
assert 'another_trigger' in agent.triggers
|
||||
assert '/test_task' in agent.triggers
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
assert agent.triggers.count('/test_task') == 1 # No duplicates
|
||||
assert len(agent.triggers) == 2
|
||||
assert 'another_trigger' in agent.triggers
|
||||
assert '/test_task' in agent.triggers
|
||||
|
||||
|
||||
def test_task_microagent_match_trigger():
|
||||
def test_task_microagent_match_trigger(temp_dir):
|
||||
"""Test that a task microagent matches its trigger correctly."""
|
||||
content = """---
|
||||
name: test_task
|
||||
@@ -337,17 +340,16 @@ inputs:
|
||||
This is a test task microagent.
|
||||
"""
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.md') as f:
|
||||
f.write(content.encode())
|
||||
f.flush()
|
||||
with open(os.path.join(temp_dir, 'test_task.md'), 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
agent = BaseMicroagent.load(f.name)
|
||||
agent = BaseMicroagent.load(os.path.join(temp_dir, 'test_task.md'))
|
||||
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
assert agent.match_trigger('/test_task') == '/test_task'
|
||||
assert agent.match_trigger(' /test_task ') == '/test_task'
|
||||
assert agent.match_trigger('This contains /test_task') == '/test_task'
|
||||
assert agent.match_trigger('/other_task') is None
|
||||
assert isinstance(agent, TaskMicroagent)
|
||||
assert agent.match_trigger('/test_task') == '/test_task'
|
||||
assert agent.match_trigger(' /test_task ') == '/test_task'
|
||||
assert agent.match_trigger('This contains /test_task') == '/test_task'
|
||||
assert agent.match_trigger('/other_task') is None
|
||||
|
||||
|
||||
def test_default_tools_microagent_exists():
|
||||
@@ -369,15 +371,12 @@ def test_default_tools_microagent_exists():
|
||||
with open(default_tools_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Verify it's a repo microagent (always activated)
|
||||
assert 'type: repo' in content, 'default-tools.md should be a repo microagent'
|
||||
assert 'command: uvx' in content, 'default-tools.md should use uvx command'
|
||||
assert 'mcp-server-fetch' in content, 'default-tools.md should use mcp-server-fetch'
|
||||
|
||||
# Verify it has the fetch tool configured
|
||||
assert 'name: "fetch"' in content, 'default-tools.md should have a fetch tool'
|
||||
assert 'command: "uvx"' in content, 'default-tools.md should use uvx command'
|
||||
assert 'args: ["mcp-server-fetch"]' in content, (
|
||||
'default-tools.md should use mcp-server-fetch'
|
||||
)
|
||||
agent = BaseMicroagent.load(default_tools_path)
|
||||
|
||||
assert isinstance(agent, RepoMicroagent)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -7,7 +7,7 @@ from openhands.microagent.types import MicroagentType
|
||||
def test_load_markdown_without_frontmatter():
|
||||
"""Test loading a markdown file without frontmatter."""
|
||||
content = '# Test Content\nThis is a test markdown file without frontmatter.'
|
||||
path = Path('test.md')
|
||||
path = Path('default.md')
|
||||
|
||||
# Load the agent from content using keyword argument
|
||||
agent = BaseMicroagent.load(path=path, file_content=content)
|
||||
@@ -26,7 +26,7 @@ def test_load_markdown_with_empty_frontmatter():
|
||||
content = (
|
||||
'---\n---\n# Test Content\nThis is a test markdown file with empty frontmatter.'
|
||||
)
|
||||
path = Path('test.md')
|
||||
path = Path('default.md')
|
||||
|
||||
# Load the agent from content using keyword argument
|
||||
agent = BaseMicroagent.load(path=path, file_content=content)
|
||||
@@ -50,12 +50,12 @@ name: custom_name
|
||||
---
|
||||
# Test Content
|
||||
This is a test markdown file with partial frontmatter."""
|
||||
path = Path('test.md')
|
||||
path = Path('custom_name.md')
|
||||
|
||||
# Load the agent from content using keyword argument
|
||||
agent = BaseMicroagent.load(path=path, file_content=content)
|
||||
|
||||
# Verify it uses provided name but default values for other fields
|
||||
# Verify it uses filename instead of provided name (filename takes precedence)
|
||||
assert isinstance(agent, RepoMicroagent)
|
||||
assert agent.name == 'custom_name'
|
||||
assert (
|
||||
@@ -77,12 +77,12 @@ version: 2.0.0
|
||||
---
|
||||
# Test Content
|
||||
This is a test markdown file with full frontmatter."""
|
||||
path = Path('test.md')
|
||||
path = Path('test_agent.md')
|
||||
|
||||
# Load the agent from content using keyword argument
|
||||
agent = BaseMicroagent.load(path=path, file_content=content)
|
||||
|
||||
# Verify all provided values are used
|
||||
# Verify filename is used for name but other metadata values are preserved
|
||||
assert isinstance(agent, RepoMicroagent)
|
||||
assert agent.name == 'test_agent'
|
||||
assert (
|
||||
|
||||
Reference in New Issue
Block a user