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:
Aleksandar
2024-05-07 12:25:35 +01:00
committed by GitHub
parent 6150ab6a3e
commit 4bf4119259
4 changed files with 134 additions and 11 deletions

View File

@@ -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):

View File

@@ -0,0 +1,5 @@
name: TypoFixerAgent
description: Fixes typos in files in the current working directory
inputs: {}
outputs:
summary: string

View 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."
}
}

View 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)