Răsfoiți Sursa

CoderAgent: Render summary prompt conditionally (#1461)

* CoderAgent: Render repo summary conditionally

* Add unittests

---------

Co-authored-by: Robert Brennan <accounts@rbren.io>
Boxuan Li 1 an în urmă
părinte
comite
c7dd443fa2

+ 14 - 0
agenthub/micro/README.md

@@ -0,0 +1,14 @@
+## Introduction
+
+This package contains definitions of micro-agents. A micro-agent is defined
+in the following structure:
+
+```
+[AgentName]
+├── agent.yaml
+└── prompt.md
+```
+
+Note that `prompt.md` could use jinja2 template syntax. During runtime, `prompt.md`
+is loaded and rendered, and used together with `agent.yaml` to initialize a
+micro-agent.

+ 2 - 0
agenthub/micro/coder/prompt.md

@@ -4,9 +4,11 @@ need to modify to complete this task:
 
 {{ state.plan.main_goal }}
 
+{% if state.inputs.summary %}
 Here's a summary of the codebase, as it relates to this task:
 
 {{ state.inputs.summary }}
+{% endif %}
 
 ## Available Actions
 {{ instructions.actions.run }}

+ 74 - 0
tests/unit/test_micro_agents.py

@@ -0,0 +1,74 @@
+import json
+import os
+from unittest.mock import MagicMock
+
+import yaml
+
+from agenthub.micro.registry import all_microagents
+from opendevin.agent import Agent
+from opendevin.plan import Plan
+from opendevin.state import State
+
+
+def test_all_agents_are_loaded():
+    full_path = os.path.join('agenthub', 'micro')
+    agent_names = set()
+    for root, _, files in os.walk(full_path):
+        for file in files:
+            if file == 'agent.yaml':
+                file_path = os.path.join(root, file)
+                with open(file_path, 'r') as yaml_file:
+                    data = yaml.safe_load(yaml_file)
+                    agent_names.add(data['name'])
+    assert agent_names == set(all_microagents.keys())
+
+
+def test_coder_agent_with_summary():
+    """
+    Coder agent should render code summary as part of prompt
+    """
+    mock_llm = MagicMock()
+    content = json.dumps({'action': 'finish', 'args': {}})
+    mock_llm.completion.return_value = {
+        'choices': [{'message': {'content': content}}]
+    }
+
+    coder_agent = Agent.get_cls('CoderAgent')(llm=mock_llm)
+    assert coder_agent is not None
+    task = 'This is a dummy task'
+    plan = Plan(task)
+    summary = 'This is a dummy summary about this repo'
+    state = State(plan, inputs={'summary': summary})
+    coder_agent.step(state)
+
+    mock_llm.completion.assert_called_once()
+    _, kwargs = mock_llm.completion.call_args
+    prompt = kwargs['messages'][0]['content']
+    assert task in prompt
+    assert "Here's a summary of the codebase, as it relates to this task" in prompt
+    assert summary in prompt
+
+
+def test_coder_agent_without_summary():
+    """
+    When there's no codebase_summary available, there shouldn't be any prompt
+    about 'code summary'
+    """
+    mock_llm = MagicMock()
+    content = json.dumps({'action': 'finish', 'args': {}})
+    mock_llm.completion.return_value = {
+        'choices': [{'message': {'content': content}}]
+    }
+
+    coder_agent = Agent.get_cls('CoderAgent')(llm=mock_llm)
+    assert coder_agent is not None
+    task = 'This is a dummy task'
+    plan = Plan(task)
+    state = State(plan)
+    coder_agent.step(state)
+
+    mock_llm.completion.assert_called_once()
+    _, kwargs = mock_llm.completion.call_args
+    prompt = kwargs['messages'][0]['content']
+    assert task in prompt
+    assert "Here's a summary of the codebase, as it relates to this task" not in prompt