1+ import re
12from pydantic import ConfigDict , Field
23
34from moatless .actions .action import Action
@@ -86,6 +87,23 @@ def _truncate_output_by_tokens(self, output: str, max_tokens: int, model: str =
8687
8788 return best_result , True
8889
90+ def _strip_ansi_codes (self , text : str ) -> str :
91+ """
92+ Strip ANSI color codes and terminal sequences from text.
93+
94+ This removes common ANSI escape sequences including:
95+ - Color codes (\033 [31m, \033 [0m, etc.)
96+ - Cursor movement (\033 [K, \r , etc.)
97+ - Bold, underline, and other formatting
98+ """
99+ if not text :
100+ return text
101+
102+ # ANSI escape sequence pattern - matches \033[ or \x1b[ followed by any characters until 'm'
103+ # Also matches common terminal control characters like \r
104+ ansi_pattern = r'\033\[[0-9;]*[mK]|\x1b\[[0-9;]*[mK]|\r'
105+ return re .sub (ansi_pattern , '' , text )
106+
89107 async def execute (self , args : ActionArguments , file_context : FileContext | None = None ) -> Observation :
90108 """Execute a Python script and return its output."""
91109 if not isinstance (args , RunPythonScriptArgs ):
@@ -109,8 +127,11 @@ async def execute(self, args: ActionArguments, file_context: FileContext | None
109127
110128 output = await self .workspace .environment .execute (command , patch = patch , fail_on_error = True )
111129
130+ # Strip ANSI codes from output
131+ clean_output = self ._strip_ansi_codes (output )
132+
112133 # Truncate output if it exceeds max_output_tokens
113- truncated_output , was_truncated = self ._truncate_output_by_tokens (output , args .max_output_tokens )
134+ truncated_output , was_truncated = self ._truncate_output_by_tokens (clean_output , args .max_output_tokens )
114135
115136 message = f"Python output:\n { truncated_output } "
116137 properties = {}
@@ -120,8 +141,11 @@ async def execute(self, args: ActionArguments, file_context: FileContext | None
120141
121142 return Observation .create (message = message , properties = properties )
122143 except EnvironmentExecutionError as e :
144+ # Strip ANSI codes from error output
145+ clean_error = self ._strip_ansi_codes (e .stderr )
146+
123147 # Also truncate error output
124- truncated_error , was_truncated = self ._truncate_output_by_tokens (e . stderr , args .max_output_tokens )
148+ truncated_error , was_truncated = self ._truncate_output_by_tokens (clean_error , args .max_output_tokens )
125149
126150 message = f"Python output:\n { truncated_error } "
127151 properties = {"fail_reason" : "execution_error" }
0 commit comments