refactor(prompt): Consolidate system prompts with Jinja inheritance (#9797)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Xingyao Wang
2025-08-12 23:04:08 -04:00
committed by GitHub
parent 500ab46918
commit 50aa014876
4 changed files with 112 additions and 181 deletions

View File

@@ -307,6 +307,87 @@ def test_prompt_manager_custom_system_prompt_filename_not_found(prompt_dir):
"""Test that PromptManager raises an error if custom system prompt file is not found."""
with pytest.raises(
FileNotFoundError,
match=r'System prompt file "non_existent\.j2" not found at .*/non_existent\.j2\. Please ensure the file exists in the prompt directory:',
match=r'Prompt file .*/non_existent\.j2 not found',
):
PromptManager(prompt_dir=prompt_dir, system_prompt_filename='non_existent.j2')
def test_jinja2_template_inheritance(prompt_dir):
"""Test that PromptManager._load_template works with Jinja2 template inclusion.
This test demonstrates that we can use {% include %} to import a base system_prompt.j2
into other templates without defining any blocks in the base template, and that
PromptManager._load_template can load these templates correctly.
"""
# Create base system prompt template (no blocks defined here)
with open(os.path.join(prompt_dir, 'system_prompt.j2'), 'w') as f:
f.write("""You are OpenHands agent, a helpful AI assistant that can interact with a computer to solve tasks.
<ROLE>
Your primary role is to assist users by executing commands, modifying code, and solving technical problems effectively.
</ROLE>
""")
# Create interactive system prompt that imports the base template and adds content
with open(os.path.join(prompt_dir, 'system_prompt_interactive.j2'), 'w') as f:
f.write("""{% include "system_prompt.j2" %}
<INTERACTION_RULES>
1. Always respond in a friendly, helpful manner
2. Ask clarifying questions when needed
3. Provide step-by-step explanations
</INTERACTION_RULES>
""")
# Create long horizon system prompt that imports the base template and adds content
with open(os.path.join(prompt_dir, 'system_prompt_long_horizon.j2'), 'w') as f:
f.write("""{% include "system_prompt.j2" %}
<TASK_MANAGEMENT>
1. Break down complex tasks into smaller steps
2. Track progress through a TODO list
3. Focus on one task at a time
</TASK_MANAGEMENT>
""")
# Test PromptManager._load_template with base system prompt
base_manager = PromptManager(prompt_dir=prompt_dir)
base_template = base_manager._load_template('system_prompt.j2')
base_msg = base_template.render().strip()
assert 'You are OpenHands agent' in base_msg
assert '<ROLE>' in base_msg
assert '<INTERACTION_RULES>' not in base_msg
assert '<TASK_MANAGEMENT>' not in base_msg
# Test PromptManager._load_template with interactive system prompt
interactive_manager = PromptManager(
prompt_dir=prompt_dir, system_prompt_filename='system_prompt_interactive.j2'
)
interactive_template = interactive_manager._load_template(
'system_prompt_interactive.j2'
)
interactive_msg = interactive_template.render().strip()
assert 'You are OpenHands agent' in interactive_msg
assert '<ROLE>' in interactive_msg
assert '<INTERACTION_RULES>' in interactive_msg
assert 'Ask clarifying questions when needed' in interactive_msg
assert '<TASK_MANAGEMENT>' not in interactive_msg
# Test PromptManager._load_template with long horizon system prompt
long_horizon_manager = PromptManager(
prompt_dir=prompt_dir, system_prompt_filename='system_prompt_long_horizon.j2'
)
long_horizon_template = long_horizon_manager._load_template(
'system_prompt_long_horizon.j2'
)
long_horizon_msg = long_horizon_template.render().strip()
assert 'You are OpenHands agent' in long_horizon_msg
assert '<ROLE>' in long_horizon_msg
assert '<INTERACTION_RULES>' not in long_horizon_msg
assert '<TASK_MANAGEMENT>' in long_horizon_msg
assert 'Track progress through a TODO list' in long_horizon_msg
# Clean up
os.remove(os.path.join(prompt_dir, 'system_prompt.j2'))
os.remove(os.path.join(prompt_dir, 'system_prompt_interactive.j2'))
os.remove(os.path.join(prompt_dir, 'system_prompt_long_horizon.j2'))