mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-01-09 14:57:59 -05:00
Introduce TypoFixerAgent for in-place typo corrections in agenthub/micro (#1613)
* Add TypoFixerAgent micro-agent to fix typos * Improve parse_response to accurately extract the first complete JSON object * Add tests for parse_response function handling complex scenarios * Fix tests and logic to use action_from_dict * Fix small formatting issues
This commit is contained in:
@@ -14,17 +14,26 @@ from .registry import all_microagents
|
||||
|
||||
|
||||
def parse_response(orig_response: str) -> Action:
|
||||
json_start = orig_response.find('{')
|
||||
json_end = orig_response.rfind('}') + 1
|
||||
response = orig_response[json_start:json_end]
|
||||
try:
|
||||
action_dict = json.loads(response)
|
||||
except json.JSONDecodeError as e:
|
||||
raise LLMOutputError(
|
||||
'Invalid JSON in response. Please make sure the response is a valid JSON object'
|
||||
) from e
|
||||
action = action_from_dict(action_dict)
|
||||
return action
|
||||
depth = 0
|
||||
start = -1
|
||||
for i, char in enumerate(orig_response):
|
||||
if char == '{':
|
||||
if depth == 0:
|
||||
start = i
|
||||
depth += 1
|
||||
elif char == '}':
|
||||
depth -= 1
|
||||
if depth == 0 and start != -1:
|
||||
response = orig_response[start : i + 1]
|
||||
try:
|
||||
action_dict = json.loads(response)
|
||||
action = action_from_dict(action_dict)
|
||||
return action
|
||||
except json.JSONDecodeError as e:
|
||||
raise LLMOutputError(
|
||||
'Invalid JSON in response. Please make sure the response is a valid JSON object.'
|
||||
) from e
|
||||
raise LLMOutputError('No valid JSON object found in response.')
|
||||
|
||||
|
||||
def my_encoder(obj):
|
||||
|
||||
5
agenthub/micro/typo_fixer_agent/agent.yaml
Normal file
5
agenthub/micro/typo_fixer_agent/agent.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
name: TypoFixerAgent
|
||||
description: Fixes typos in files in the current working directory
|
||||
inputs: {}
|
||||
outputs:
|
||||
summary: string
|
||||
46
agenthub/micro/typo_fixer_agent/prompt.md
Normal file
46
agenthub/micro/typo_fixer_agent/prompt.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Task
|
||||
You are a proofreader tasked with fixing typos in the files in your current working directory. Your goal is to:
|
||||
1. Scan the files for typos
|
||||
2. Overwrite the files with the typos fixed
|
||||
3. Provide a summary of the typos fixed
|
||||
|
||||
## Available Actions
|
||||
{{ instructions.actions.read }}
|
||||
{{ instructions.actions.write }}
|
||||
{{ instructions.actions.run }}
|
||||
{{ instructions.actions.think }}
|
||||
{{ instructions.actions.finish }}
|
||||
|
||||
To complete this task:
|
||||
1. Use the `read` action to read the contents of the files in your current working directory. Make sure to provide the file path in the format `'./file_name.ext'`.
|
||||
2. Use the `think` action to analyze the contents and identify typos.
|
||||
3. Use the `write` action to create new versions of the files with the typos fixed.
|
||||
- Overwrite the original files with the corrected content. Make sure to provide the file path in the format `'./file_name.ext'`.
|
||||
4. Use the `think` action to generate a summary of the typos fixed, including the original and fixed versions of each typo, and the file(s) they were found in.
|
||||
5. Use the `finish` action to return the summary in the `outputs.summary` field.
|
||||
|
||||
Do NOT finish until you have fixed all the typos and generated a summary.
|
||||
|
||||
## History
|
||||
{{ instructions.history_truncated }}
|
||||
{{ to_json(state.history[-5:]) }}
|
||||
|
||||
## Format
|
||||
{{ instructions.format.action }}
|
||||
|
||||
For example, if you want to use the read action to read the contents of a file named example.txt, your response should look like this:
|
||||
{
|
||||
"action": "read",
|
||||
"args": {
|
||||
"path": "./example.txt"
|
||||
}
|
||||
}
|
||||
|
||||
Similarly, if you want to use the write action to write content to a file named output.txt, your response should look like this:
|
||||
{
|
||||
"action": "write",
|
||||
"args": {
|
||||
"path": "./output.txt",
|
||||
"content": "This is the content to be written to the file."
|
||||
}
|
||||
}
|
||||
63
tests/unit/test_response_parsing.py
Normal file
63
tests/unit/test_response_parsing.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import pytest
|
||||
from agenthub.micro.agent import parse_response, LLMOutputError
|
||||
from opendevin.events.action import (
|
||||
AgentThinkAction,
|
||||
FileWriteAction,
|
||||
)
|
||||
|
||||
|
||||
def test_parse_single_complete_json():
|
||||
input_response = """
|
||||
{
|
||||
"action": "think",
|
||||
"args": {
|
||||
"thought": "The following typos were fixed:\\n* 'futur' -> 'future'\\n* 'imagin' -> 'imagine'\\n* 'techological' -> 'technological'\\n* 'responsability' -> 'responsibility'\\nThe corrected file is ./short_essay.txt."
|
||||
}
|
||||
}
|
||||
"""
|
||||
expected = AgentThinkAction(thought="The following typos were fixed:\n* 'futur' -> 'future'\n* 'imagin' -> 'imagine'\n* 'techological' -> 'technological'\n* 'responsability' -> 'responsibility'\nThe corrected file is ./short_essay.txt.")
|
||||
assert parse_response(input_response) == expected
|
||||
|
||||
|
||||
def test_parse_json_with_surrounding_text():
|
||||
input_response = """
|
||||
Some initial text that is not JSON formatted.
|
||||
{
|
||||
"action": "write",
|
||||
"args": {
|
||||
"path": "./updated_file.txt",
|
||||
"content": "Updated text content here..."
|
||||
}
|
||||
}
|
||||
Some trailing text that is also not JSON formatted.
|
||||
"""
|
||||
expected = FileWriteAction(path="./updated_file.txt", content="Updated text content here...")
|
||||
assert parse_response(input_response) == expected
|
||||
|
||||
|
||||
def test_parse_first_of_multiple_jsons():
|
||||
input_response = """
|
||||
I will firstly do
|
||||
{
|
||||
"action": "write",
|
||||
"args": {
|
||||
"path": "./short_essay.txt",
|
||||
"content": "Text content here..."
|
||||
}
|
||||
}
|
||||
Then I will continue with
|
||||
{
|
||||
"action": "think",
|
||||
"args": {
|
||||
"thought": "This should not be parsed."
|
||||
}
|
||||
}
|
||||
"""
|
||||
expected = FileWriteAction(path="./short_essay.txt", content="Text content here...")
|
||||
assert parse_response(input_response) == expected
|
||||
|
||||
|
||||
def test_invalid_json_raises_error():
|
||||
input_response = '{"action": "write", "args": { "path": "./short_essay.txt", "content": "Missing closing brace"'
|
||||
with pytest.raises(LLMOutputError):
|
||||
parse_response(input_response)
|
||||
Reference in New Issue
Block a user