diff --git a/docs/app/agent_files/_plugin.py b/docs/app/agent_files/_plugin.py index f3d56ab827a..f602dc9f4ea 100644 --- a/docs/app/agent_files/_plugin.py +++ b/docs/app/agent_files/_plugin.py @@ -809,6 +809,26 @@ def generate_llms_full_txt( return (Path("llms-full.txt"), "\n".join(lines).rstrip() + "\n") +def markdown_path_for_trailing_slash_url(path: Path) -> Path: + """Return the static-asset path that serves the trailing-slash URL variant. + + A request for `/.md` is served from the file at `/.md` on disk, + making the trailing-slash URL `/` resolve to the same content as the + no-slash URL `.md`. + + Example: + >>> markdown_path_for_trailing_slash_url(Path("ai/overview.md")) + PosixPath('ai/overview/.md') + + Args: + path: The markdown file path. + + Returns: + The asset path under which to serve the trailing-slash variant. + """ + return path.with_suffix("") / ".md" + + def generate_agent_files() -> tuple[tuple[Path, str | bytes], ...]: markdown_file_entries = generate_markdown_file_entries() markdown_index_entries = tuple( @@ -827,9 +847,19 @@ def generate_agent_files() -> tuple[tuple[Path, str | bytes], ...]: (entry.url_path, generate_markdown_file_content(entry)) for entry in markdown_file_entries ) - return ( + + all_markdown_files = [ *markdown_files, *dynamic_api_reference_files, + ] + + return ( + *all_markdown_files, + # Such that `path/.md` would resolve to the same content as `path.md` + *[ + (markdown_path_for_trailing_slash_url(path), content) + for path, content in all_markdown_files + ], generate_llms_txt(( *markdown_index_entries, *dynamic_api_reference_entries, diff --git a/docs/app/tests/test_agent_files.py b/docs/app/tests/test_agent_files.py index f9124aa503e..96fc6f2d831 100644 --- a/docs/app/tests/test_agent_files.py +++ b/docs/app/tests/test_agent_files.py @@ -7,10 +7,12 @@ MarkdownFileEntry, MarkdownIndexEntry, dynamic_api_reference_index_entries, + generate_agent_files, generate_dynamic_api_reference_files, generate_llms_full_txt, generate_llms_txt, generate_markdown_file_content, + markdown_path_for_trailing_slash_url, ) @@ -343,3 +345,28 @@ def test_generate_llms_full_txt_stitches_markdown_docs(monkeypatch, tmp_path): "`reflex_base.event.EventHandler`" ) in content assert "For AI agents: the complete documentation index" not in content + + +def test_markdown_path_for_trailing_slash_url(): + """The trailing-slash variant nests `.md` under the page name.""" + assert markdown_path_for_trailing_slash_url(Path("ai/overview.md")) == Path( + "ai/overview/.md" + ) + assert markdown_path_for_trailing_slash_url(Path("api-reference/var.md")) == Path( + "api-reference/var/.md" + ) + + +def test_generate_agent_files_emits_trailing_slash_variants(): + """Every markdown asset has a trailing-slash twin with identical content.""" + files = dict(generate_agent_files()) + + markdown_paths = [ + path for path in files if path.suffix == ".md" and path.name != ".md" + ] + assert markdown_paths, "expected at least one markdown asset" + + for path in markdown_paths: + twin = markdown_path_for_trailing_slash_url(path) + assert twin in files, f"missing trailing-slash twin for {path}" + assert files[twin] == files[path], f"content mismatch for {twin}"