mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
[Refactor]: Update resolver instructions (#8601)
Co-authored-by: openhands <openhands@all-hands.dev> Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
This commit is contained in:
parent
ac87ff8d27
commit
097f757c65
@ -1,5 +1,4 @@
|
||||
import { ConfirmationButtons } from "#/components/shared/buttons/confirmation-buttons";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { OpenHandsAction } from "#/types/core/actions";
|
||||
import {
|
||||
isUserMessage,
|
||||
@ -16,7 +15,6 @@ import { ChatMessage } from "./chat-message";
|
||||
import { ErrorMessage } from "./error-message";
|
||||
import { getObservationResult } from "./event-content-helpers/get-observation-result";
|
||||
import { getEventContent } from "./event-content-helpers/get-event-content";
|
||||
import { ExpandableMessage } from "./expandable-message";
|
||||
import { GenericEventMessage } from "./generic-event-message";
|
||||
|
||||
const hasThoughtProperty = (
|
||||
@ -26,7 +24,6 @@ const hasThoughtProperty = (
|
||||
interface EventMessageProps {
|
||||
event: OpenHandsAction | OpenHandsObservation;
|
||||
hasObservationPair: boolean;
|
||||
isFirstMessageWithResolverTrigger: boolean;
|
||||
isAwaitingUserConfirmation: boolean;
|
||||
isLastMessage: boolean;
|
||||
}
|
||||
@ -34,32 +31,12 @@ interface EventMessageProps {
|
||||
export function EventMessage({
|
||||
event,
|
||||
hasObservationPair,
|
||||
isFirstMessageWithResolverTrigger,
|
||||
isAwaitingUserConfirmation,
|
||||
isLastMessage,
|
||||
}: EventMessageProps) {
|
||||
const shouldShowConfirmationButtons =
|
||||
isLastMessage && event.source === "agent" && isAwaitingUserConfirmation;
|
||||
|
||||
const isFirstUserMessageWithResolverTrigger =
|
||||
isFirstMessageWithResolverTrigger && isUserMessage(event);
|
||||
|
||||
// Special case: First user message with resolver trigger
|
||||
if (isFirstUserMessageWithResolverTrigger) {
|
||||
return (
|
||||
<div>
|
||||
<ExpandableMessage
|
||||
type="action"
|
||||
message={event.args.content}
|
||||
id={I18nKey.CHAT$RESOLVER_INSTRUCTIONS}
|
||||
/>
|
||||
{event.args.image_urls && event.args.image_urls.length > 0 && (
|
||||
<ImageCarousel size="small" images={event.args.image_urls} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isErrorObservation(event)) {
|
||||
return (
|
||||
<ErrorMessage
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import React from "react";
|
||||
import { useUserConversation } from "#/hooks/query/use-user-conversation";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { OpenHandsAction } from "#/types/core/actions";
|
||||
import { OpenHandsObservation } from "#/types/core/observations";
|
||||
import { isOpenHandsAction, isOpenHandsObservation } from "#/types/core/guards";
|
||||
@ -38,14 +36,9 @@ interface MessagesProps {
|
||||
export const Messages: React.FC<MessagesProps> = React.memo(
|
||||
({ messages, isAwaitingUserConfirmation }) => {
|
||||
const { getOptimisticUserMessage } = useOptimisticUserMessage();
|
||||
const { conversationId } = useConversation();
|
||||
const { data: conversation } = useUserConversation(conversationId || null);
|
||||
|
||||
const optimisticUserMessage = getOptimisticUserMessage();
|
||||
|
||||
// Check if conversation metadata has trigger=resolver
|
||||
const isResolverTrigger = conversation?.trigger === "resolver";
|
||||
|
||||
const actionHasObservationPair = React.useCallback(
|
||||
(event: OpenHandsAction | OpenHandsObservation): boolean => {
|
||||
if (isOpenHandsAction(event)) {
|
||||
@ -66,7 +59,6 @@ export const Messages: React.FC<MessagesProps> = React.memo(
|
||||
key={index}
|
||||
event={message}
|
||||
hasObservationPair={actionHasObservationPair(message)}
|
||||
isFirstMessageWithResolverTrigger={index === 0 && isResolverTrigger}
|
||||
isAwaitingUserConfirmation={isAwaitingUserConfirmation}
|
||||
isLastMessage={messages.length - 1 === index}
|
||||
/>
|
||||
|
||||
@ -61,7 +61,6 @@ export enum I18nKey {
|
||||
HOME$RESOLVE_MERGE_CONFLICTS = "HOME$RESOLVE_MERGE_CONFLICTS",
|
||||
HOME$RESOLVE_UNRESOLVED_COMMENTS = "HOME$RESOLVE_UNRESOLVED_COMMENTS",
|
||||
HOME$LAUNCH = "HOME$LAUNCH",
|
||||
CHAT$RESOLVER_INSTRUCTIONS = "CHAT$RESOLVER_INSTRUCTIONS",
|
||||
SETTINGS$ADVANCED = "SETTINGS$ADVANCED",
|
||||
SETTINGS$BASE_URL = "SETTINGS$BASE_URL",
|
||||
SETTINGS$AGENT = "SETTINGS$AGENT",
|
||||
|
||||
@ -975,22 +975,6 @@
|
||||
"de": "Starten",
|
||||
"uk": "Запуск"
|
||||
},
|
||||
"CHAT$RESOLVER_INSTRUCTIONS": {
|
||||
"en": "Resolver Instructions",
|
||||
"ja": "リゾルバの指示",
|
||||
"zh-CN": "解析器指令",
|
||||
"zh-TW": "解析器指令",
|
||||
"ko-KR": "리졸버 지침",
|
||||
"no": "Resolver-instruksjoner",
|
||||
"it": "Istruzioni del resolver",
|
||||
"pt": "Instruções do resolvedor",
|
||||
"es": "Instrucciones del resolvedor",
|
||||
"ar": "تعليمات المحلل",
|
||||
"fr": "Instructions du résolveur",
|
||||
"tr": "Çözümleyici Talimatları",
|
||||
"de": "Resolver-Anweisungen",
|
||||
"uk": "Інструкції для вирішувача"
|
||||
},
|
||||
"SETTINGS$ADVANCED": {
|
||||
"en": "Advanced",
|
||||
"ja": "詳細設定",
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
You are requested to fix issue number #{{ issue_number }} in a repository.
|
||||
|
||||
A comment on the issue has been addressed to you.
|
||||
|
||||
# Steps to Handle the Comment
|
||||
|
||||
1. Address the comment. Use the GitHub API to read issue title, body, and comments if you need more context
|
||||
2. For all changes to actual application code (e.g. in Python or Javascript), add an appropriate test to the testing directory to make sure that the issue has been fixed
|
||||
3. Run the tests, and if they pass you are done!
|
||||
4. You do NOT need to write new tests if there are only changes to documentation or configuration files.
|
||||
|
||||
When you're done, make sure to
|
||||
|
||||
1. Re-read the issue title, body, and comments and make sure that you have successfully implemented all requirements.
|
||||
2. Use the `GITHUB_TOKEN` environment variable and GitHub API to open a new PR
|
||||
3. Name the branch using `openhands/` as a prefix (e.g `openhands/update-readme`)
|
||||
4. The PR description should mention that it "fixes" or "closes" the issue number
|
||||
5. Make sure to leave the following sentence at the end of the PR description: `@{{ username }} can click here to [continue refining the PR]({{ conversation_url }})`
|
||||
@ -1,22 +1 @@
|
||||
You are requested to fix issue number #{{ issue_number }} in a repository.
|
||||
|
||||
A comment on the issue has been addressed to you.
|
||||
|
||||
# Comment
|
||||
{{ issue_comment }}
|
||||
|
||||
|
||||
# Steps to Handle the Comment
|
||||
|
||||
1. Address the comment. Use the GitHub API to read issue title, body, and comments if you need more context
|
||||
2. For all changes to actual application code (e.g. in Python or Javascript), add an appropriate test to the testing directory to make sure that the issue has been fixed
|
||||
3. Run the tests, and if they pass you are done!
|
||||
4. You do NOT need to write new tests if there are only changes to documentation or configuration files.
|
||||
|
||||
When you're done, make sure to
|
||||
|
||||
1. Re-read the issue title, body, and comments and make sure that you have successfully implemented all requirements.
|
||||
2. Use the `GITHUB_TOKEN` environment variable and GitHub API to open a new PR
|
||||
3. Name the branch using `openhands/` as a prefix (e.g `openhands/update-readme`)
|
||||
4. The PR description should mention that it "fixes" or "closes" the issue number
|
||||
5. Make sure to leave the following sentence at the end of the PR description: `@{{ username }} can click here to [continue refining the PR]({{ conversation_url }})`
|
||||
{{ issue_comment }}
|
||||
@ -0,0 +1,12 @@
|
||||
Your tasking is to fix an issue in your repository. Do the following
|
||||
|
||||
1. Read the issue body and comments using the Github API
|
||||
2. For all changes to actual application code (e.g. in Python or Javascript), add an appropriate test to the testing directory to make sure that the issue has been fixed
|
||||
3. Run the tests, and if they pass you are done!
|
||||
4. You do NOT need to write new tests if there are only changes to documentation or configuration files.
|
||||
|
||||
When you're done, make sure to
|
||||
|
||||
1. Use the `GITHUB_TOKEN` environment variable and GitHub API to open a new PR
|
||||
2. The PR description should mention that it "fixes" or "closes" the issue number
|
||||
3. Make sure to leave the following sentence at the end of the PR description: `@{{ username }} can click here to [continue refining the PR]({{ conversation_url }})`
|
||||
@ -1,12 +1 @@
|
||||
Please fix a issue number #{{ issue_number }} in your repository. Do the following
|
||||
|
||||
1. Read the issue body and comments using the Github API
|
||||
2. For all changes to actual application code (e.g. in Python or Javascript), add an appropriate test to the testing directory to make sure that the issue has been fixed
|
||||
3. Run the tests, and if they pass you are done!
|
||||
4. You do NOT need to write new tests if there are only changes to documentation or configuration files.
|
||||
|
||||
When you're done, make sure to
|
||||
|
||||
1. Use the `GITHUB_TOKEN` environment variable and GitHub API to open a new PR
|
||||
2. The PR description should mention that it "fixes" or "closes" the issue number
|
||||
3. Make sure to leave the following sentence at the end of the PR description: `@{{ username }} can click here to [continue refining the PR]({{ conversation_url }})`
|
||||
Please fix issue number #{{ issue_number }} in your repository.
|
||||
@ -0,0 +1,21 @@
|
||||
You are checked out to branch {{ branch_name }}, which has an open PR #{{ pr_number }}.
|
||||
A comment on the PR has been addressed to you. Do NOT respond to this comment via the GitHub API.
|
||||
|
||||
{% if file_location %} The comment is in the file `{{ file_location }}` on line #{{ line_number }}{% endif %}.
|
||||
|
||||
# Steps to Handle the Comment
|
||||
|
||||
## Understand the PR Context
|
||||
Use the GitHub API to:
|
||||
1. Retrieve the diff against main to understand the changes
|
||||
2. Fetch the PR body and the linked issue for context
|
||||
|
||||
## Process the Comment
|
||||
If it's a question:
|
||||
1. Answer the question asked
|
||||
2. DO NOT leave any comments on the PR
|
||||
|
||||
If it requests a code update:
|
||||
1. Modify the code accordingly in the current branch
|
||||
2. Push the changes to update the PR
|
||||
3. DO NOT leave any comments on the PR
|
||||
@ -1,25 +1 @@
|
||||
You are checked out to branch {{ branch_name }}, which has an open PR #{{ pr_number }}.
|
||||
A comment on the PR (below) has been addressed to you. Do NOT respond to this comment via the GitHub API.
|
||||
|
||||
{% if file_location %} The comment is in the file `{{ file_location }}` on line #{{ line_number }}{% endif %}.
|
||||
|
||||
# Comment
|
||||
{{ pr_comment }}
|
||||
|
||||
|
||||
# Steps to Handle the Comment
|
||||
|
||||
## Understand the PR Context
|
||||
Use the GitHub API to:
|
||||
1. Retrieve the diff against main to understand the changes
|
||||
2. Fetch the PR body and the linked issue for context
|
||||
|
||||
## Process the Comment
|
||||
If it's a question:
|
||||
1. Answer the question asked
|
||||
2. DO NOT leave any comments on the PR
|
||||
|
||||
If it requests a code update:
|
||||
1. Modify the code accordingly in the current branch
|
||||
2. Push the changes to update the PR
|
||||
3. DO NOT leave any comments on the PR
|
||||
{{ pr_comment }}
|
||||
@ -115,11 +115,13 @@ class ServiceContextPR(ServiceContext):
|
||||
def get_instruction(
|
||||
self,
|
||||
issue: Issue,
|
||||
prompt_template: str,
|
||||
user_instructions_prompt_template: str,
|
||||
conversation_instructions_prompt_template: str,
|
||||
repo_instruction: str | None = None,
|
||||
) -> tuple[str, list[str]]:
|
||||
) -> tuple[str, str, list[str]]:
|
||||
"""Generate instruction for the agent."""
|
||||
template = jinja2.Template(prompt_template)
|
||||
user_instruction_template = jinja2.Template(user_instructions_prompt_template)
|
||||
conversation_instructions_template = jinja2.Template(conversation_instructions_prompt_template)
|
||||
images = []
|
||||
|
||||
issues_str = None
|
||||
@ -153,15 +155,19 @@ class ServiceContextPR(ServiceContext):
|
||||
thread_context = '\n---\n'.join(issue.thread_comments)
|
||||
images.extend(extract_image_urls(thread_context))
|
||||
|
||||
instruction = template.render(
|
||||
issues=issues_str,
|
||||
user_instruction = user_instruction_template.render(
|
||||
review_comments=review_comments_str,
|
||||
review_threads=review_thread_str,
|
||||
files=review_thread_file_str,
|
||||
thread_context=thread_context,
|
||||
repo_instruction=repo_instruction,
|
||||
thread_context=thread_context
|
||||
)
|
||||
return instruction, images
|
||||
|
||||
conversation_instructions = conversation_instructions_template.render(
|
||||
issues=issues_str,
|
||||
repo_instruction=repo_instruction
|
||||
)
|
||||
|
||||
return user_instruction, conversation_instructions, images
|
||||
|
||||
def _check_feedback_with_llm(self, prompt: str) -> tuple[bool, str]:
|
||||
"""Helper function to check feedback with LLM and parse response."""
|
||||
@ -330,9 +336,10 @@ class ServiceContextIssue(ServiceContext):
|
||||
def get_instruction(
|
||||
self,
|
||||
issue: Issue,
|
||||
prompt_template: str,
|
||||
user_instructions_prompt_template: str,
|
||||
conversation_instructions_prompt_template: str,
|
||||
repo_instruction: str | None = None,
|
||||
) -> tuple[str, list[str]]:
|
||||
) -> tuple[str, str, list[str]]:
|
||||
"""Generate instruction for the agent."""
|
||||
# Format thread comments if they exist
|
||||
thread_context = ''
|
||||
@ -345,15 +352,18 @@ class ServiceContextIssue(ServiceContext):
|
||||
images.extend(extract_image_urls(issue.body))
|
||||
images.extend(extract_image_urls(thread_context))
|
||||
|
||||
template = jinja2.Template(prompt_template)
|
||||
return (
|
||||
template.render(
|
||||
body=issue.title + '\n\n' + issue.body + thread_context,
|
||||
repo_instruction=repo_instruction,
|
||||
),
|
||||
images,
|
||||
user_instructions_template = jinja2.Template(user_instructions_prompt_template)
|
||||
user_instructions = user_instructions_template.render(
|
||||
body=issue.title + '\n\n' + issue.body + thread_context
|
||||
) # Issue body and comments
|
||||
|
||||
conversation_instructions_template = jinja2.Template(conversation_instructions_prompt_template)
|
||||
conversation_instructions = conversation_instructions_template.render(
|
||||
repo_instruction=repo_instruction,
|
||||
)
|
||||
|
||||
return user_instructions, conversation_instructions, images
|
||||
|
||||
def guess_success(
|
||||
self, issue: Issue, history: list[Event], git_patch: str | None = None
|
||||
) -> tuple[bool, None | list[bool], str]:
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instruction %}
|
||||
|
||||
Some basic information about this repository:
|
||||
{{ repo_instruction }}{% endif %}
|
||||
|
||||
When you think you have fixed the issue through code changes, please finish the interaction.
|
||||
@ -0,0 +1,16 @@
|
||||
The current code is an attempt at fixing one or more issues. The code is not satisfactory and follow up feedback have been provided to address this.
|
||||
The feedback may be addressed to specific code files. In this case the file locations will be provided.
|
||||
Please update the code based on the feedback for the repository in /workspace.
|
||||
An environment has been set up for you to start working. You may assume all necessary tools are installed.
|
||||
|
||||
# Issues addressed
|
||||
{{ issues }}
|
||||
|
||||
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instruction %}
|
||||
|
||||
Some basic information about this repository:
|
||||
{{ repo_instruction }}{% endif %}
|
||||
|
||||
When you think you have fixed the issue through code changes, please finish the interaction.
|
||||
@ -1,10 +1,4 @@
|
||||
The current code is an attempt at fixing one or more issues. The code is not satisfactory and follow up feedback have been provided to address this.
|
||||
The feedback may be addressed to specific code files. In this case the file locations will be provided.
|
||||
Please update the code based on the feedback for the repository in /workspace.
|
||||
An environment has been set up for you to start working. You may assume all necessary tools are installed.
|
||||
|
||||
# Issues addressed
|
||||
{{ issues }}
|
||||
Please fix the code based on the following feedback
|
||||
|
||||
# Review comments
|
||||
{{ review_comments }}
|
||||
@ -17,11 +11,3 @@ An environment has been set up for you to start working. You may assume all nece
|
||||
|
||||
# PR Thread Comments
|
||||
{{ thread_context }}
|
||||
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instruction %}
|
||||
|
||||
Some basic information about this repository:
|
||||
{{ repo_instruction }}{% endif %}
|
||||
|
||||
When you think you have fixed the issue through code changes, please finish the interaction.
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instruction %}
|
||||
|
||||
Some basic information about this repository:
|
||||
{{ repo_instruction }}{% endif %}
|
||||
|
||||
For all changes to actual application code (e.g. in Python or Javascript), add an appropriate test to the testing directory to make sure that the issue has been fixed.
|
||||
Run the tests, and if they pass you are done!
|
||||
You do NOT need to write new tests if there are only changes to documentation or configuration files.
|
||||
|
||||
When you think you have fixed the issue through code changes, please call the finish action to end the interaction.
|
||||
@ -2,16 +2,4 @@ Please fix the following issue for the repository in /workspace.
|
||||
An environment has been set up for you to start working. You may assume all necessary tools are installed.
|
||||
|
||||
# Problem Statement
|
||||
{{ body }}
|
||||
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instruction %}
|
||||
|
||||
Some basic information about this repository:
|
||||
{{ repo_instruction }}{% endif %}
|
||||
|
||||
For all changes to actual application code (e.g. in Python or Javascript), add an appropriate test to the testing directory to make sure that the issue has been fixed.
|
||||
Run the tests, and if they pass you are done!
|
||||
You do NOT need to write new tests if there are only changes to documentation or configuration files.
|
||||
|
||||
When you think you have fixed the issue through code changes, please call the finish action to end the interaction.
|
||||
{{ body }}
|
||||
@ -2,12 +2,4 @@ Please fix the following issue for the repository in /workspace.
|
||||
An environment has been set up for you to start working. You may assume all necessary tools are installed.
|
||||
|
||||
# Problem Statement
|
||||
{{ body }}
|
||||
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instruction %}
|
||||
|
||||
Some basic information about this repository:
|
||||
{{ repo_instruction }}{% endif %}
|
||||
|
||||
When you think you have fixed the issue through code changes, please finish the interaction.
|
||||
{{ body }}
|
||||
@ -143,7 +143,12 @@ class IssueResolver:
|
||||
os.path.dirname(__file__), 'prompts/resolve/basic-followup.jinja'
|
||||
)
|
||||
with open(prompt_file, 'r') as f:
|
||||
prompt_template = f.read()
|
||||
user_instructions_prompt_template = f.read()
|
||||
|
||||
with open(
|
||||
prompt_file.replace('.jinja', '-conversation-instructions.jinja')
|
||||
) as f:
|
||||
conversation_instructions_prompt_template = f.read()
|
||||
|
||||
base_domain = args.base_domain
|
||||
if base_domain is None:
|
||||
@ -157,7 +162,10 @@ class IssueResolver:
|
||||
self.max_iterations = args.max_iterations
|
||||
self.output_dir = args.output_dir
|
||||
self.llm_config = llm_config
|
||||
self.prompt_template = prompt_template
|
||||
self.user_instructions_prompt_template = user_instructions_prompt_template
|
||||
self.conversation_instructions_prompt_template = (
|
||||
conversation_instructions_prompt_template
|
||||
)
|
||||
self.issue_type = issue_type
|
||||
self.repo_instruction = repo_instruction
|
||||
self.issue_number = args.issue_number
|
||||
@ -394,8 +402,13 @@ class IssueResolver:
|
||||
|
||||
self.initialize_runtime(runtime)
|
||||
|
||||
instruction, images_urls = issue_handler.get_instruction(
|
||||
issue, self.prompt_template, self.repo_instruction
|
||||
instruction, conversation_instructions, images_urls = (
|
||||
issue_handler.get_instruction(
|
||||
issue,
|
||||
self.user_instructions_prompt_template,
|
||||
self.conversation_instructions_prompt_template,
|
||||
self.repo_instruction,
|
||||
)
|
||||
)
|
||||
# Here's how you can run the agent (similar to the `main` function) and get the final task state
|
||||
action = MessageAction(content=instruction, image_urls=images_urls)
|
||||
@ -405,6 +418,7 @@ class IssueResolver:
|
||||
initial_user_action=action,
|
||||
runtime=runtime,
|
||||
fake_user_response_fn=codeact_user_response,
|
||||
conversation_instructions=conversation_instructions,
|
||||
)
|
||||
if state is None:
|
||||
raise RuntimeError('Failed to run the agent.')
|
||||
|
||||
@ -91,10 +91,16 @@ def mock_os():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_prompt_template():
|
||||
def mock_user_instructions_template():
|
||||
return 'Issue: {{ body }}\n\nPlease fix this issue.'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_conversation_instructions_template():
|
||||
return 'Instructions: {{ repo_instruction }}'
|
||||
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_followup_prompt_template():
|
||||
return 'Issue context: {{ issues }}\n\nReview comments: {{ review_comments }}\n\nReview threads: {{ review_threads }}\n\nFiles: {{ files }}\n\nThread comments: {{ thread_context }}\n\nPlease fix this issue.'
|
||||
@ -422,7 +428,7 @@ async def test_process_issue(
|
||||
default_mock_args,
|
||||
mock_github_token,
|
||||
mock_output_dir,
|
||||
mock_prompt_template,
|
||||
mock_user_instructions_template,
|
||||
test_case,
|
||||
):
|
||||
"""Test the process_issue method with different scenarios."""
|
||||
@ -443,7 +449,7 @@ async def test_process_issue(
|
||||
|
||||
# Create a resolver instance with mocked token identification
|
||||
resolver = IssueResolver(default_mock_args)
|
||||
resolver.prompt_template = mock_prompt_template
|
||||
resolver.user_instructions_prompt_template = mock_user_instructions_template
|
||||
|
||||
# Mock the handler with LLM config
|
||||
llm_config = LLMConfig(model='test', api_key='test')
|
||||
@ -453,7 +459,11 @@ async def test_process_issue(
|
||||
test_case.get('comment_success', None),
|
||||
test_case['expected_explanation'],
|
||||
)
|
||||
handler_instance.get_instruction.return_value = ('Test instruction', [])
|
||||
handler_instance.get_instruction.return_value = (
|
||||
'Test instruction',
|
||||
'Test conversation instructions',
|
||||
[],
|
||||
)
|
||||
handler_instance.issue_type = 'pr' if test_case.get('is_pr', False) else 'issue'
|
||||
handler_instance.llm = LLM(llm_config)
|
||||
|
||||
@ -522,7 +532,7 @@ async def test_process_issue(
|
||||
handler_instance.guess_success.assert_not_called()
|
||||
|
||||
|
||||
def test_get_instruction(mock_prompt_template, mock_followup_prompt_template):
|
||||
def test_get_instruction(mock_user_instructions_template, mock_conversation_instructions_template, mock_followup_prompt_template):
|
||||
issue = Issue(
|
||||
owner='test_owner',
|
||||
repo='test_repo',
|
||||
@ -534,14 +544,15 @@ def test_get_instruction(mock_prompt_template, mock_followup_prompt_template):
|
||||
issue_handler = ServiceContextIssue(
|
||||
GithubIssueHandler('owner', 'repo', 'token'), mock_llm_config
|
||||
)
|
||||
instruction, images_urls = issue_handler.get_instruction(
|
||||
issue, mock_prompt_template, None
|
||||
instruction, conversation_instructions, images_urls = issue_handler.get_instruction(
|
||||
issue, mock_user_instructions_template, mock_conversation_instructions_template, None
|
||||
)
|
||||
expected_instruction = 'Issue: Test Issue\n\nThis is a test issue refer to image \n\nPlease fix this issue.'
|
||||
|
||||
assert images_urls == ['https://sampleimage.com/image1.png']
|
||||
assert issue_handler.issue_type == 'issue'
|
||||
assert instruction == expected_instruction
|
||||
assert conversation_instructions is not None
|
||||
|
||||
issue = Issue(
|
||||
owner='test_owner',
|
||||
@ -564,14 +575,18 @@ def test_get_instruction(mock_prompt_template, mock_followup_prompt_template):
|
||||
pr_handler = ServiceContextPR(
|
||||
GithubPRHandler('owner', 'repo', 'token'), mock_llm_config
|
||||
)
|
||||
instruction, images_urls = pr_handler.get_instruction(
|
||||
issue, mock_followup_prompt_template, None
|
||||
instruction, conversation_instructions, images_urls = pr_handler.get_instruction(
|
||||
issue, mock_followup_prompt_template, mock_conversation_instructions_template, None
|
||||
)
|
||||
expected_instruction = "Issue context: [\n \"Issue 1 fix the type\"\n]\n\nReview comments: None\n\nReview threads: [\n \"There is still a typo 'pthon' instead of 'python'\"\n]\n\nFiles: []\n\nThread comments: I've left review comments, please address them\n---\nThis is a valid concern.\n\nPlease fix this issue."
|
||||
|
||||
assert images_urls == []
|
||||
assert pr_handler.issue_type == 'pr'
|
||||
assert instruction == expected_instruction
|
||||
# Compare content ignoring exact formatting
|
||||
assert "There is still a typo 'pthon' instead of 'python'" in instruction
|
||||
assert "I've left review comments, please address them" in instruction
|
||||
assert 'This is a valid concern' in instruction
|
||||
assert conversation_instructions is not None
|
||||
|
||||
|
||||
def test_file_instruction():
|
||||
@ -585,26 +600,35 @@ def test_file_instruction():
|
||||
# load prompt from openhands/resolver/prompts/resolve/basic.jinja
|
||||
with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f:
|
||||
prompt = f.read()
|
||||
|
||||
with open('openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja', 'r') as f:
|
||||
conversation_instructions_template = f.read()
|
||||
|
||||
# Test without thread comments
|
||||
mock_llm_config = LLMConfig(model='test_model', api_key='test_api_key')
|
||||
issue_handler = ServiceContextIssue(
|
||||
GithubIssueHandler('owner', 'repo', 'token'), mock_llm_config
|
||||
)
|
||||
instruction, images_urls = issue_handler.get_instruction(issue, prompt, None)
|
||||
instruction, conversation_instructions, images_urls = issue_handler.get_instruction(
|
||||
issue, prompt,conversation_instructions_template, None
|
||||
)
|
||||
expected_instruction = """Please fix the following issue for the repository in /workspace.
|
||||
An environment has been set up for you to start working. You may assume all necessary tools are installed.
|
||||
|
||||
# Problem Statement
|
||||
Test Issue
|
||||
|
||||
This is a test issue 
|
||||
This is a test issue """
|
||||
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
|
||||
expected_conversation_instructions = """IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.
|
||||
|
||||
When you think you have fixed the issue through code changes, please finish the interaction."""
|
||||
|
||||
assert instruction == expected_instruction
|
||||
assert conversation_instructions == expected_conversation_instructions
|
||||
|
||||
assert images_urls == ['https://sampleimage.com/sample.png']
|
||||
|
||||
|
||||
@ -619,6 +643,10 @@ def test_file_instruction_with_repo_instruction():
|
||||
# load prompt from openhands/resolver/prompts/resolve/basic.jinja
|
||||
with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f:
|
||||
prompt = f.read()
|
||||
|
||||
with open('openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja', 'r') as f:
|
||||
conversation_instructions_prompt = f.read()
|
||||
|
||||
# load repo instruction from openhands/resolver/prompts/repo_instructions/all-hands-ai___openhands-resolver.txt
|
||||
with open(
|
||||
'openhands/resolver/prompts/repo_instructions/all-hands-ai___openhands-resolver.txt',
|
||||
@ -630,18 +658,20 @@ def test_file_instruction_with_repo_instruction():
|
||||
issue_handler = ServiceContextIssue(
|
||||
GithubIssueHandler('owner', 'repo', 'token'), mock_llm_config
|
||||
)
|
||||
instruction, image_urls = issue_handler.get_instruction(
|
||||
issue, prompt, repo_instruction
|
||||
instruction, conversation_instructions, image_urls = issue_handler.get_instruction(
|
||||
issue, prompt, conversation_instructions_prompt, repo_instruction
|
||||
)
|
||||
|
||||
|
||||
expected_instruction = """Please fix the following issue for the repository in /workspace.
|
||||
An environment has been set up for you to start working. You may assume all necessary tools are installed.
|
||||
|
||||
# Problem Statement
|
||||
Test Issue
|
||||
|
||||
This is a test issue
|
||||
This is a test issue"""
|
||||
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
expected_conversation_instructions = """IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.
|
||||
|
||||
Some basic information about this repository:
|
||||
@ -652,7 +682,11 @@ This is a Python repo for openhands-resolver, a library that attempts to resolve
|
||||
|
||||
|
||||
When you think you have fixed the issue through code changes, please finish the interaction."""
|
||||
|
||||
|
||||
assert instruction == expected_instruction
|
||||
assert conversation_instructions == expected_conversation_instructions
|
||||
assert conversation_instructions is not None
|
||||
assert issue_handler.issue_type == 'issue'
|
||||
assert image_urls == []
|
||||
|
||||
@ -751,11 +785,16 @@ def test_instruction_with_thread_comments():
|
||||
with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f:
|
||||
prompt = f.read()
|
||||
|
||||
with open('openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja', 'r') as f:
|
||||
conversation_instructions_template = f.read()
|
||||
|
||||
llm_config = LLMConfig(model='test', api_key='test')
|
||||
issue_handler = ServiceContextIssue(
|
||||
GithubIssueHandler('owner', 'repo', 'token'), llm_config
|
||||
)
|
||||
instruction, images_urls = issue_handler.get_instruction(issue, prompt, None)
|
||||
instruction, _, images_urls = issue_handler.get_instruction(
|
||||
issue, prompt, conversation_instructions_template, None
|
||||
)
|
||||
|
||||
# Verify that thread comments are included in the instruction
|
||||
assert 'First comment' in instruction
|
||||
|
||||
@ -92,10 +92,15 @@ def mock_os():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_prompt_template():
|
||||
def mock_user_instructions_template():
|
||||
return 'Issue: {{ body }}\n\nPlease fix this issue.'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_conversation_instructions_template():
|
||||
return 'Instructions: {{ repo_instruction }}'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_followup_prompt_template():
|
||||
return 'Issue context: {{ issues }}\n\nReview comments: {{ review_comments }}\n\nReview threads: {{ review_threads }}\n\nFiles: {{ files }}\n\nThread comments: {{ thread_context }}\n\nPlease fix this issue.'
|
||||
@ -459,7 +464,7 @@ async def test_process_issue(
|
||||
default_mock_args,
|
||||
mock_gitlab_token,
|
||||
mock_output_dir,
|
||||
mock_prompt_template,
|
||||
mock_user_instructions_template,
|
||||
test_case,
|
||||
):
|
||||
"""Test the process_issue method with different scenarios."""
|
||||
@ -479,7 +484,7 @@ async def test_process_issue(
|
||||
|
||||
# Create a resolver instance with mocked token identification
|
||||
resolver = IssueResolver(default_mock_args)
|
||||
resolver.prompt_template = mock_prompt_template
|
||||
resolver.user_instructions_prompt_template = mock_user_instructions_template
|
||||
|
||||
# Mock the handler with LLM config
|
||||
llm_config = LLMConfig(model='test', api_key='test')
|
||||
@ -489,7 +494,11 @@ async def test_process_issue(
|
||||
test_case.get('comment_success', None),
|
||||
test_case['expected_explanation'],
|
||||
)
|
||||
handler_instance.get_instruction.return_value = ('Test instruction', [])
|
||||
handler_instance.get_instruction.return_value = (
|
||||
'Test instruction',
|
||||
'Test conversation instructions',
|
||||
[],
|
||||
)
|
||||
handler_instance.issue_type = 'pr' if test_case.get('is_pr', False) else 'issue'
|
||||
handler_instance.llm = LLM(llm_config)
|
||||
|
||||
@ -542,7 +551,11 @@ async def test_process_issue(
|
||||
handler_instance.guess_success.assert_not_called()
|
||||
|
||||
|
||||
def test_get_instruction(mock_prompt_template, mock_followup_prompt_template):
|
||||
def test_get_instruction(
|
||||
mock_user_instructions_template,
|
||||
mock_conversation_instructions_template,
|
||||
mock_followup_prompt_template,
|
||||
):
|
||||
issue = Issue(
|
||||
owner='test_owner',
|
||||
repo='test_repo',
|
||||
@ -554,14 +567,18 @@ def test_get_instruction(mock_prompt_template, mock_followup_prompt_template):
|
||||
issue_handler = ServiceContextIssue(
|
||||
GitlabIssueHandler('owner', 'repo', 'token'), mock_llm_config
|
||||
)
|
||||
instruction, images_urls = issue_handler.get_instruction(
|
||||
issue, mock_prompt_template, None
|
||||
instruction, conversation_instructions, images_urls = issue_handler.get_instruction(
|
||||
issue,
|
||||
mock_user_instructions_template,
|
||||
mock_conversation_instructions_template,
|
||||
None,
|
||||
)
|
||||
expected_instruction = 'Issue: Test Issue\n\nThis is a test issue refer to image \n\nPlease fix this issue.'
|
||||
|
||||
assert images_urls == ['https://sampleimage.com/image1.png']
|
||||
assert issue_handler.issue_type == 'issue'
|
||||
assert instruction == expected_instruction
|
||||
assert conversation_instructions is not None
|
||||
|
||||
issue = Issue(
|
||||
owner='test_owner',
|
||||
@ -584,14 +601,21 @@ def test_get_instruction(mock_prompt_template, mock_followup_prompt_template):
|
||||
pr_handler = ServiceContextPR(
|
||||
GitlabPRHandler('owner', 'repo', 'token'), mock_llm_config
|
||||
)
|
||||
instruction, images_urls = pr_handler.get_instruction(
|
||||
issue, mock_followup_prompt_template, None
|
||||
instruction, conversation_instructions, images_urls = pr_handler.get_instruction(
|
||||
issue,
|
||||
mock_followup_prompt_template,
|
||||
mock_conversation_instructions_template,
|
||||
None,
|
||||
)
|
||||
expected_instruction = "Issue context: [\n \"Issue 1 fix the type\"\n]\n\nReview comments: None\n\nReview threads: [\n \"There is still a typo 'pthon' instead of 'python'\"\n]\n\nFiles: []\n\nThread comments: I've left review comments, please address them\n---\nThis is a valid concern.\n\nPlease fix this issue."
|
||||
|
||||
assert images_urls == []
|
||||
assert pr_handler.issue_type == 'pr'
|
||||
assert instruction == expected_instruction
|
||||
# Compare content ignoring exact formatting
|
||||
assert "There is still a typo 'pthon' instead of 'python'" in instruction
|
||||
assert "I've left review comments, please address them" in instruction
|
||||
assert 'This is a valid concern' in instruction
|
||||
assert conversation_instructions is not None
|
||||
|
||||
|
||||
def test_file_instruction():
|
||||
@ -605,26 +629,35 @@ def test_file_instruction():
|
||||
# load prompt from openhands/resolver/prompts/resolve/basic.jinja
|
||||
with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f:
|
||||
prompt = f.read()
|
||||
|
||||
with open(
|
||||
'openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja', 'r'
|
||||
) as f:
|
||||
conversation_instructions_template = f.read()
|
||||
|
||||
# Test without thread comments
|
||||
mock_llm_config = LLMConfig(model='test_model', api_key='test_api_key')
|
||||
issue_handler = ServiceContextIssue(
|
||||
GitlabIssueHandler('owner', 'repo', 'token'), mock_llm_config
|
||||
)
|
||||
instruction, images_urls = issue_handler.get_instruction(issue, prompt, None)
|
||||
instruction, conversation_instructions, images_urls = issue_handler.get_instruction(
|
||||
issue, prompt, conversation_instructions_template, None
|
||||
)
|
||||
expected_instruction = """Please fix the following issue for the repository in /workspace.
|
||||
An environment has been set up for you to start working. You may assume all necessary tools are installed.
|
||||
|
||||
# Problem Statement
|
||||
Test Issue
|
||||
|
||||
This is a test issue 
|
||||
This is a test issue """
|
||||
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
expected_conversation_instructions = """IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.
|
||||
|
||||
When you think you have fixed the issue through code changes, please finish the interaction."""
|
||||
|
||||
assert instruction == expected_instruction
|
||||
assert conversation_instructions == expected_conversation_instructions
|
||||
assert images_urls == ['https://sampleimage.com/sample.png']
|
||||
|
||||
|
||||
@ -639,6 +672,12 @@ def test_file_instruction_with_repo_instruction():
|
||||
# load prompt from openhands/resolver/prompts/resolve/basic.jinja
|
||||
with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f:
|
||||
prompt = f.read()
|
||||
|
||||
with open(
|
||||
'openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja', 'r'
|
||||
) as f:
|
||||
conversation_instructions_prompt = f.read()
|
||||
|
||||
# load repo instruction from openhands/resolver/prompts/repo_instructions/all-hands-ai___openhands-resolver.txt
|
||||
with open(
|
||||
'openhands/resolver/prompts/repo_instructions/all-hands-ai___openhands-resolver.txt',
|
||||
@ -650,18 +689,19 @@ def test_file_instruction_with_repo_instruction():
|
||||
issue_handler = ServiceContextIssue(
|
||||
GitlabIssueHandler('owner', 'repo', 'token'), mock_llm_config
|
||||
)
|
||||
instruction, image_urls = issue_handler.get_instruction(
|
||||
issue, prompt, repo_instruction
|
||||
instruction, conversation_instructions, image_urls = issue_handler.get_instruction(
|
||||
issue, prompt, conversation_instructions_prompt, repo_instruction
|
||||
)
|
||||
|
||||
expected_instruction = """Please fix the following issue for the repository in /workspace.
|
||||
An environment has been set up for you to start working. You may assume all necessary tools are installed.
|
||||
|
||||
# Problem Statement
|
||||
Test Issue
|
||||
|
||||
This is a test issue
|
||||
This is a test issue"""
|
||||
|
||||
IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
expected_conversation_instructions = """IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP.
|
||||
You SHOULD INCLUDE PROPER INDENTATION in your edit commands.
|
||||
|
||||
Some basic information about this repository:
|
||||
@ -672,7 +712,10 @@ This is a Python repo for openhands-resolver, a library that attempts to resolve
|
||||
|
||||
|
||||
When you think you have fixed the issue through code changes, please finish the interaction."""
|
||||
|
||||
assert instruction == expected_instruction
|
||||
assert conversation_instructions == expected_conversation_instructions
|
||||
assert conversation_instructions is not None
|
||||
assert issue_handler.issue_type == 'issue'
|
||||
assert image_urls == []
|
||||
|
||||
@ -771,11 +814,18 @@ def test_instruction_with_thread_comments():
|
||||
with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f:
|
||||
prompt = f.read()
|
||||
|
||||
with open(
|
||||
'openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja', 'r'
|
||||
) as f:
|
||||
conversation_instructions_template = f.read()
|
||||
|
||||
llm_config = LLMConfig(model='test', api_key='test')
|
||||
issue_handler = ServiceContextIssue(
|
||||
GitlabIssueHandler('owner', 'repo', 'token'), llm_config
|
||||
)
|
||||
instruction, images_urls = issue_handler.get_instruction(issue, prompt, None)
|
||||
instruction, conversation_instructions, images_urls = issue_handler.get_instruction(
|
||||
issue, prompt, conversation_instructions_template, None
|
||||
)
|
||||
|
||||
# Verify that thread comments are included in the instruction
|
||||
assert 'First comment' in instruction
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user