from dataclasses import dataclass from pathlib import Path import yaml from jinja2 import StrictUndefined, Template from minisweagent.agents.default import AgentConfig @dataclass class MockOutput: """Mock output object for testing the template""" returncode: int output: str exception_info: str = "" def test_observation_template_short_output(): """Test that short output (< 10000 chars) is displayed in full""" # Load the swebench config config_path = ( Path(__file__).parent.parent.parent / "src" / "minisweagent" / "config" / "benchmarks" / "swebench_backticks.yaml" ) with open(config_path) as f: config = yaml.safe_load(f) # Extract the template (now in model section) template_str = config["model"]["observation_template"] template = Template(template_str, undefined=StrictUndefined) # Create mock output with short content output = MockOutput(returncode=0, output="Success! Operation completed.\nWarning: minor issue") # Render the template result = template.render(output=output) # Verify the result contains all parts and no truncation assert "" in result assert "0" in result assert "" in result assert "Success! Operation completed." in result assert "Warning: minor issue" in result # Should not contain truncation elements for short output assert "" not in result assert "" not in result assert "" not in result assert "" not in result def test_observation_template_long_output(): """Test that long output (> 10000 chars) is truncated with head/tail format""" # Load the swebench config config_path = ( Path(__file__).parent.parent.parent / "src" / "minisweagent" / "config" / "benchmarks" / "swebench_backticks.yaml" ) with open(config_path) as f: config = yaml.safe_load(f) # Extract the template (now in model section) template_str = config["model"]["observation_template"] template = Template(template_str, undefined=StrictUndefined) # Create mock output with long content long_output = "A" * 8000 + "B" * 3000 # 11000 characters total # Total will be > 10000 chars output = MockOutput(returncode=1, output=long_output) # Render the template result = template.render(output=output) # Should contain truncation elements for long output assert "" in result assert "The output of your last command was too long" in result assert "" in result assert "" in result assert "characters elided" in result assert "" in result # Should still contain the basic structure assert "" in result assert "1" in result # Verify the head contains first part of output head_start = result.find("") head_end = result.find("") head_content = result[head_start:head_end] assert "AAAA" in head_content # Should contain start of output # Verify the tail contains last part of output tail_start = result.find("") tail_end = result.find("") tail_content = result[tail_start:tail_end] assert "BBBB" in tail_content # Should contain end of output def test_observation_template_edge_case_exactly_10000_chars(): """Test the boundary case where output is around 10000 characters""" # Load the swebench config config_path = ( Path(__file__).parent.parent.parent / "src" / "minisweagent" / "config" / "benchmarks" / "swebench_backticks.yaml" ) with open(config_path) as f: config = yaml.safe_load(f) # Extract the template (now in model section) template_str = config["model"]["observation_template"] template = Template(template_str, undefined=StrictUndefined) # Use a large amount of data that will definitely exceed 10000 chars when rendered output = MockOutput(returncode=0, output="X" * 10000) # Render the template result = template.render(output=output) # Should use truncated format for large output assert "" in result assert "" in result assert "" in result assert "" in result # The X's should still be present in head or tail assert "XXXX" in result def test_observation_template_just_under_10000_chars(): """Test that smaller output shows full output without truncation""" # Load the swebench config config_path = ( Path(__file__).parent.parent.parent / "src" / "minisweagent" / "config" / "benchmarks" / "swebench_backticks.yaml" ) with open(config_path) as f: config = yaml.safe_load(f) # Extract the template (now in model section) template_str = config["model"]["observation_template"] template = Template(template_str, undefined=StrictUndefined) # Use a reasonably sized output that should be well under 10000 chars when rendered output = MockOutput(returncode=0, output="Y" * 8000) # Render the template result = template.render(output=output) # Should show full output without truncation assert "" not in result assert "" not in result assert "" not in result assert "" not in result assert "Y" * 8000 in result def test_agent_config_requires_templates(): """Test that AgentConfig now requires all template fields (no defaults in code)""" import pytest from pydantic import ValidationError # AgentConfig should require all template fields now (Pydantic raises ValidationError) with pytest.raises(ValidationError, match="validation error"): AgentConfig()