@@ -40,22 +40,25 @@ public static void RenderBlockWithIndentation(LlmMarkdownRenderer renderer, Mark
4040
4141	/// <summary> 
4242	/// Converts relative URLs to absolute URLs using BuildContext.CanonicalBaseUrl for better LLM consumption. 
43- 	/// For documentation URLs,  converts them  to .md format for consistency with LLM-generated files . 
43+ 	/// Also  converts localhost URLs  to canonical URLs . 
4444	/// </summary> 
4545	public  static string ?  MakeAbsoluteUrl ( LlmMarkdownRenderer  renderer ,  string ?  url ) 
4646	{ 
4747		if  ( renderer . BuildContext . CanonicalBaseUrl  ==  null ) 
4848			return  url ; 
4949
50- 		// For documentation URLs (starting with /docs/), convert to .md format for LLM consistency 
51- 		// BUT exclude files with extensions (images, PDFs, etc.) which should keep their original extensions 
52- 		if  ( ! string . IsNullOrEmpty ( url )  &&  url . StartsWith ( "/docs/" ,  StringComparison . Ordinal )  &&  ! HasFileExtension ( url ) ) 
50+ 		// Convert localhost URLs to canonical URLs for LLM consumption 
51+ 		if  ( ! string . IsNullOrEmpty ( url )  &&  url . StartsWith ( "http://localhost" ,  StringComparison . OrdinalIgnoreCase ) ) 
5352		{ 
54- 			var  markdownUrl  =  ConvertToMarkdownUrl ( url ) ; 
55- 			return  MakeAbsoluteUrl ( renderer . BuildContext . CanonicalBaseUrl ,  markdownUrl ) ; 
53+ 			if  ( Uri . TryCreate ( url ,  UriKind . Absolute ,  out  var  localhostUri )  && 
54+ 				localhostUri . AbsolutePath . StartsWith ( "/docs/" ,  StringComparison . Ordinal ) ) 
55+ 			{ 
56+ 				// Replace localhost with canonical base URL 
57+ 				var  canonicalUrl  =  new  Uri ( renderer . BuildContext . CanonicalBaseUrl ,  localhostUri . AbsolutePath ) ; 
58+ 				return  canonicalUrl . ToString ( ) ; 
59+ 			} 
5660		} 
5761
58- 		// For other URLs (images, external links), use regular absolute URL conversion 
5962		return  MakeAbsoluteUrl ( renderer . BuildContext . CanonicalBaseUrl ,  url ) ; 
6063	} 
6164
@@ -81,68 +84,7 @@ public static void RenderBlockWithIndentation(LlmMarkdownRenderer renderer, Mark
8184		} 
8285	} 
8386
84- 	/// <summary> 
85- 	/// Converts documentation URLs to absolute markdown URLs for LLM consumption 
86- 	/// </summary> 
87- 	public  static string  MakeAbsoluteMarkdownUrl ( Uri  baseUri ,  string ?  url ) 
88- 	{ 
89- 		if  ( string . IsNullOrEmpty ( url ) ) 
90- 			return  string . Empty ; 
91- 
92- 		// Convert to .md URL for LLM consumption 
93- 		var  markdownUrl  =  ConvertToMarkdownUrl ( url ) ; 
94- 
95- 		// Use the existing absolute URL logic 
96- 		return  MakeAbsoluteUrl ( baseUri ,  markdownUrl )  ??  markdownUrl ; 
97- 	} 
9887
99- 	/// <summary> 
100- 	/// Converts documentation URL paths to .md file paths for LLM consumption 
101- 	/// </summary> 
102- 	private  static string  ConvertToMarkdownUrl ( string  url ) 
103- 	{ 
104- 		var  cleanUrl  =  url . TrimStart ( '/' ) ; 
105- 
106- 		// Remove "docs/" prefix if present for the markdown filename, then add it back 
107- 		var  markdownPath  =  cleanUrl ; 
108- 		if  ( markdownPath . StartsWith ( "docs/" ,  StringComparison . Ordinal ) ) 
109- 			markdownPath  =  markdownPath . Substring ( 5 ) ; 
110- 
111- 		// Convert directory URLs to .md files 
112- 		if  ( markdownPath . EndsWith ( '/' ) ) 
113- 			markdownPath  =  markdownPath . TrimEnd ( '/' )  +  ".md" ; 
114- 		else  if  ( ! markdownPath . EndsWith ( ".md" ,  StringComparison . Ordinal ) ) 
115- 			markdownPath  +=  ".md" ; 
116- 
117- 		return  $ "/docs/{ markdownPath } "; 
118- 	} 
119- 
120- 	/// <summary> 
121- 	/// Checks if a URL path points to a file with an extension (not a documentation page) 
122- 	/// </summary> 
123- 	private  static bool  HasFileExtension ( string  path ) 
124- 	{ 
125- 		try 
126- 		{ 
127- 			// Try to parse as URI to handle query parameters and fragments 
128- 			if  ( Uri . TryCreate ( path ,  UriKind . RelativeOrAbsolute ,  out  var  uri ) ) 
129- 			{ 
130- 				// Get the path component without query/fragment 
131- 				var  pathOnly  =  uri . GetLeftPart ( UriPartial . Path ) ; 
132- 				var  ext  =  Path . GetExtension ( pathOnly ) ; 
133- 				return  ! string . IsNullOrEmpty ( ext ) ; 
134- 			} 
135- 
136- 			// Fallback to direct path parsing 
137- 			var  extension  =  Path . GetExtension ( path ) ; 
138- 			return  ! string . IsNullOrEmpty ( extension ) ; 
139- 		} 
140- 		catch 
141- 		{ 
142- 			// If parsing fails, assume it's a documentation page 
143- 			return  false ; 
144- 		} 
145- 	} 
14688
14789} 
14890
0 commit comments