diff --git a/frontend/src/components/features/chat/event-message.tsx b/frontend/src/components/features/chat/event-message.tsx
index 1bb62bd237..1d4a3ac51c 100644
--- a/frontend/src/components/features/chat/event-message.tsx
+++ b/frontend/src/components/features/chat/event-message.tsx
@@ -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 (
-
-
- {event.args.image_urls && event.args.image_urls.length > 0 && (
-
- )}
-
- );
- }
-
if (isErrorObservation(event)) {
return (
= 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 = React.memo(
key={index}
event={message}
hasObservationPair={actionHasObservationPair(message)}
- isFirstMessageWithResolverTrigger={index === 0 && isResolverTrigger}
isAwaitingUserConfirmation={isAwaitingUserConfirmation}
isLastMessage={messages.length - 1 === index}
/>
diff --git a/frontend/src/i18n/declaration.ts b/frontend/src/i18n/declaration.ts
index ef7e403d82..b0a0690bb7 100644
--- a/frontend/src/i18n/declaration.ts
+++ b/frontend/src/i18n/declaration.ts
@@ -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",
diff --git a/frontend/src/i18n/translation.json b/frontend/src/i18n/translation.json
index 6efd38b8ab..99334d8ba9 100644
--- a/frontend/src/i18n/translation.json
+++ b/frontend/src/i18n/translation.json
@@ -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": "詳細設定",
diff --git a/openhands/integrations/templates/resolver/github/issue_comment_conversation_instructions.j2 b/openhands/integrations/templates/resolver/github/issue_comment_conversation_instructions.j2
new file mode 100644
index 0000000000..3862a97858
--- /dev/null
+++ b/openhands/integrations/templates/resolver/github/issue_comment_conversation_instructions.j2
@@ -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 }})`
diff --git a/openhands/integrations/templates/resolver/github/issue_comment_prompt.j2 b/openhands/integrations/templates/resolver/github/issue_comment_prompt.j2
index e6f74a5996..352927cfd7 100644
--- a/openhands/integrations/templates/resolver/github/issue_comment_prompt.j2
+++ b/openhands/integrations/templates/resolver/github/issue_comment_prompt.j2
@@ -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 }}
\ No newline at end of file
diff --git a/openhands/integrations/templates/resolver/github/issue_labeled_conversation_instructions.j2 b/openhands/integrations/templates/resolver/github/issue_labeled_conversation_instructions.j2
new file mode 100644
index 0000000000..aac2b542dc
--- /dev/null
+++ b/openhands/integrations/templates/resolver/github/issue_labeled_conversation_instructions.j2
@@ -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 }})`
diff --git a/openhands/integrations/templates/resolver/github/issue_labeled_prompt.j2 b/openhands/integrations/templates/resolver/github/issue_labeled_prompt.j2
index d034b28802..eece89fec2 100644
--- a/openhands/integrations/templates/resolver/github/issue_labeled_prompt.j2
+++ b/openhands/integrations/templates/resolver/github/issue_labeled_prompt.j2
@@ -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.
\ No newline at end of file
diff --git a/openhands/integrations/templates/resolver/github/pr_update_conversation_instructions.j2 b/openhands/integrations/templates/resolver/github/pr_update_conversation_instructions.j2
new file mode 100644
index 0000000000..0362e597ce
--- /dev/null
+++ b/openhands/integrations/templates/resolver/github/pr_update_conversation_instructions.j2
@@ -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
diff --git a/openhands/integrations/templates/resolver/github/pr_update_prompt.j2 b/openhands/integrations/templates/resolver/github/pr_update_prompt.j2
index 347bc6bde4..ff1ef88774 100644
--- a/openhands/integrations/templates/resolver/github/pr_update_prompt.j2
+++ b/openhands/integrations/templates/resolver/github/pr_update_prompt.j2
@@ -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 }}
\ No newline at end of file
diff --git a/openhands/resolver/interfaces/issue_definitions.py b/openhands/resolver/interfaces/issue_definitions.py
index 15a9f7cb2d..b24b813b8b 100644
--- a/openhands/resolver/interfaces/issue_definitions.py
+++ b/openhands/resolver/interfaces/issue_definitions.py
@@ -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]:
diff --git a/openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja b/openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja
new file mode 100644
index 0000000000..9d240983db
--- /dev/null
+++ b/openhands/resolver/prompts/resolve/basic-conversation-instructions.jinja
@@ -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.
\ No newline at end of file
diff --git a/openhands/resolver/prompts/resolve/basic-followup-conversation-instructions.jinja b/openhands/resolver/prompts/resolve/basic-followup-conversation-instructions.jinja
new file mode 100644
index 0000000000..eceef63f82
--- /dev/null
+++ b/openhands/resolver/prompts/resolve/basic-followup-conversation-instructions.jinja
@@ -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.
\ No newline at end of file
diff --git a/openhands/resolver/prompts/resolve/basic-followup.jinja b/openhands/resolver/prompts/resolve/basic-followup.jinja
index b7bdc2ae9e..c696a88b52 100644
--- a/openhands/resolver/prompts/resolve/basic-followup.jinja
+++ b/openhands/resolver/prompts/resolve/basic-followup.jinja
@@ -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.
diff --git a/openhands/resolver/prompts/resolve/basic-with-tests-conversation-instructions.jinja b/openhands/resolver/prompts/resolve/basic-with-tests-conversation-instructions.jinja
new file mode 100644
index 0000000000..86a89397bc
--- /dev/null
+++ b/openhands/resolver/prompts/resolve/basic-with-tests-conversation-instructions.jinja
@@ -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.
diff --git a/openhands/resolver/prompts/resolve/basic-with-tests.jinja b/openhands/resolver/prompts/resolve/basic-with-tests.jinja
index 595489c428..4f3e5b2c0b 100644
--- a/openhands/resolver/prompts/resolve/basic-with-tests.jinja
+++ b/openhands/resolver/prompts/resolve/basic-with-tests.jinja
@@ -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 }}
\ No newline at end of file
diff --git a/openhands/resolver/prompts/resolve/basic.jinja b/openhands/resolver/prompts/resolve/basic.jinja
index a5bb806cc4..4f3e5b2c0b 100644
--- a/openhands/resolver/prompts/resolve/basic.jinja
+++ b/openhands/resolver/prompts/resolve/basic.jinja
@@ -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 }}
\ No newline at end of file
diff --git a/openhands/resolver/resolve_issue.py b/openhands/resolver/resolve_issue.py
index 5446539efe..a209e5d2e3 100644
--- a/openhands/resolver/resolve_issue.py
+++ b/openhands/resolver/resolve_issue.py
@@ -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.')
diff --git a/tests/unit/resolver/github/test_resolve_issues.py b/tests/unit/resolver/github/test_resolve_issues.py
index 99bcc61adf..0f2cafa829 100644
--- a/tests/unit/resolver/github/test_resolve_issues.py
+++ b/tests/unit/resolver/github/test_resolve_issues.py
@@ -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
diff --git a/tests/unit/resolver/gitlab/test_gitlab_resolve_issues.py b/tests/unit/resolver/gitlab/test_gitlab_resolve_issues.py
index edfbf822a7..1369deb5eb 100644
--- a/tests/unit/resolver/gitlab/test_gitlab_resolve_issues.py
+++ b/tests/unit/resolver/gitlab/test_gitlab_resolve_issues.py
@@ -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