diff --git a/lib/crewai-tools/src/crewai_tools/generate_tool_specs.py b/lib/crewai-tools/src/crewai_tools/generate_tool_specs.py index 9e1847271..0faf1c6f3 100644 --- a/lib/crewai-tools/src/crewai_tools/generate_tool_specs.py +++ b/lib/crewai-tools/src/crewai_tools/generate_tool_specs.py @@ -180,7 +180,7 @@ class ToolSpecExtractor: return json_schema def save_to_json(self, output_path: str) -> None: - with open(output_path, "w", encoding="utf-8") as f: + with open(output_path, "w", encoding="utf-8", newline="\n") as f: json.dump({"tools": self.tools_spec}, f, indent=2, sort_keys=True) diff --git a/lib/crewai-tools/tests/test_generate_tool_specs.py b/lib/crewai-tools/tests/test_generate_tool_specs.py index 2f56ed1e6..e5c3169ec 100644 --- a/lib/crewai-tools/tests/test_generate_tool_specs.py +++ b/lib/crewai-tools/tests/test_generate_tool_specs.py @@ -192,3 +192,28 @@ def test_save_to_json(extractor, tmp_path): assert len(data["tools"]) == 1 assert data["tools"][0]["humanized_name"] == "Test Tool" assert data["tools"][0]["run_params_schema"][0]["name"] == "param1" + + +def test_save_to_json_uses_lf_line_endings(extractor, tmp_path): + """Verify save_to_json writes LF (\\n) line endings, not CRLF (\\r\\n). + + Regression test for https://github.com/crewAIInc/crewAI/issues/4737. + On Windows, open() in text mode defaults to CRLF, which causes every + line to appear modified in git diff when the committed file uses LF. + """ + extractor.tools_spec = [ + { + "name": "TestTool", + "humanized_name": "Test Tool", + "description": "A test tool", + "run_params_schema": [], + } + ] + + file_path = tmp_path / "output.json" + extractor.save_to_json(str(file_path)) + + # Read in binary mode to inspect raw line endings + raw_bytes = file_path.read_bytes() + assert b"\r\n" not in raw_bytes, "File contains CRLF line endings; expected LF only" + assert b"\n" in raw_bytes, "File should contain at least one newline"