diff --git a/README.md b/README.md index be6ade32..f4e4f223 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,14 @@ Install `mint` from https://mintlify.com/docs/installation uv sync --all-groups ``` -4. **Use the docs CLI tool:** +4. **Install Mintlify CLI** + + The docs CLI uses parts of the Mintlify CLI so you need to install that too. + ```bash + npm i -g mint + ``` + +5. **Use the docs CLI tool:** After setup, you'll have access to the `docs` command: ```bash diff --git a/pipeline/core/builder.py b/pipeline/core/builder.py index f73b3fb6..482ad6e7 100644 --- a/pipeline/core/builder.py +++ b/pipeline/core/builder.py @@ -49,64 +49,54 @@ def __init__(self, src_dir: Path, build_dir: Path) -> None: ".yml", ".yaml", ".css", + ".js", } def build_all(self) -> None: """Build all documentation files from source to build directory. - This method clears the build directory and copies all supported files - from the source directory, maintaining the directory structure. + This method clears the build directory and creates version-specific builds + for both Python and JavaScript documentation. The process includes: 1. Clearing the existing build directory - 2. Recreating the build directory - 3. Collecting all files to process - 4. Processing files with a progress bar - 5. Copying only files with supported extensions + 2. Building Python version with python/ prefix + 3. Building JavaScript version with javascript/ prefix + 4. Copying shared files (images, configs, etc.) Displays: - A progress bar showing build progress and file counts. + Progress bars showing build progress for each version. """ - logger.info("Building from %s to %s", self.src_dir, self.build_dir) + logger.info( + "Building versioned documentation from %s to %s", + self.src_dir, + self.build_dir, + ) # Clear build directory if self.build_dir.exists(): shutil.rmtree(self.build_dir) self.build_dir.mkdir(parents=True, exist_ok=True) - # Collect all files to process - all_files = [ - file_path for file_path in self.src_dir.rglob("*") if file_path.is_file() - ] + # Build LangGraph versioned content (oss/ -> oss/python/ and oss/javascript/) + logger.info("Building LangGraph Python version...") + self._build_langgraph_version("oss/python", "python") - if not all_files: - logger.info("No files found to build") - return + logger.info("Building LangGraph JavaScript version...") + self._build_langgraph_version("oss/javascript", "js") - # Process files with progress bar - copied_count: int = 0 - skipped_count: int = 0 + # Build unversioned content (same content regardless of version) + logger.info("Building LangGraph Platform content...") + self._build_unversioned_content("langgraph-platform", "langgraph-platform") - with tqdm( - total=len(all_files), - desc="Building files", - unit="file", - ncols=80, - bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}]", - ) as pbar: - for file_path in all_files: - result = self._build_file_with_progress(file_path, pbar) - if result: - copied_count += 1 - else: - skipped_count += 1 - pbar.update(1) + logger.info("Building LangChain Labs content...") + self._build_unversioned_content("labs", "labs") - logger.info( - "✅ Build complete: %d files copied, %d files skipped", - copied_count, - skipped_count, - ) + # Copy shared files (docs.json, images, etc.) + logger.info("Copying shared files...") + self._copy_shared_files() + + logger.info("✅ New structure build complete") def _convert_yaml_to_json(self, yaml_file_path: Path, output_path: Path) -> None: """Convert a YAML file to JSON format. @@ -137,7 +127,9 @@ def _convert_yaml_to_json(self, yaml_file_path: Path, output_path: Path) -> None logger.exception("Failed to convert %s to JSON", yaml_file_path) raise - def _process_markdown_content(self, content: str, file_path: Path) -> str: + def _process_markdown_content( + self, content: str, file_path: Path, target_language: str | None = None + ) -> str: """Process markdown content with preprocessing. This method applies preprocessing (cross-reference resolution and @@ -146,18 +138,23 @@ def _process_markdown_content(self, content: str, file_path: Path) -> str: Args: content: The markdown content to process. file_path: Path to the source file (for error reporting). + target_language: Target language for conditional blocks ("python" or "js"). Returns: The processed markdown content. """ try: # Apply markdown preprocessing - return preprocess_markdown(content, file_path) + return preprocess_markdown( + content, file_path, target_language=target_language + ) except Exception: logger.exception("Failed to process markdown content from %s", file_path) raise - def _process_markdown_file(self, input_path: Path, output_path: Path) -> None: + def _process_markdown_file( + self, input_path: Path, output_path: Path, target_language: str | None = None + ) -> None: """Process a markdown file with preprocessing and copy to output. This method reads a markdown file, applies preprocessing (cross-reference @@ -167,6 +164,7 @@ def _process_markdown_file(self, input_path: Path, output_path: Path) -> None: Args: input_path: Path to the source markdown file. output_path: Path where the processed file should be written. + target_language: Target language for conditional blocks ("python" or "js"). """ try: # Read the source markdown content @@ -174,7 +172,9 @@ def _process_markdown_file(self, input_path: Path, output_path: Path) -> None: content = f.read() # Apply markdown preprocessing - processed_content = self._process_markdown_content(content, input_path) + processed_content = self._process_markdown_content( + content, input_path, target_language + ) # Convert .md to .mdx if needed if input_path.suffix.lower() == ".md": @@ -318,3 +318,263 @@ def build_files(self, file_paths: list[Path]) -> None: copied_count, skipped_count, ) + + def _build_langgraph_version(self, output_dir: str, target_language: str) -> None: + """Build LangGraph (oss/) content for a specific version. + + Args: + output_dir: Output directory (e.g., "langgraph/python", "langgraph/javascript"). + target_language: Target language for conditional blocks ("python" or "js"). + """ + # Only process files in the oss/ directory + oss_dir = self.src_dir / "oss" + if not oss_dir.exists(): + logger.warning("oss/ directory not found, skipping LangGraph build") + return + + all_files = [ + file_path + for file_path in oss_dir.rglob("*") + if file_path.is_file() and not self._is_shared_file(file_path) + ] + + if not all_files: + logger.info("No files found in oss/ directory for %s", output_dir) + return + + # Process files with progress bar + copied_count: int = 0 + skipped_count: int = 0 + + with tqdm( + total=len(all_files), + desc=f"Building {output_dir} files", + unit="file", + ncols=80, + bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}]", + ) as pbar: + for file_path in all_files: + # Calculate relative path from oss/ directory + relative_path = file_path.relative_to(oss_dir) + # Build to output_dir/ (not output_dir/oss/) + output_path = self.build_dir / output_dir / relative_path + + result = self._build_single_file( + file_path, + output_path, + target_language, + pbar, + f"{output_dir}/{relative_path}", + ) + if result: + copied_count += 1 + else: + skipped_count += 1 + pbar.update(1) + + logger.info( + "✅ %s complete: %d files copied, %d files skipped", + output_dir, + copied_count, + skipped_count, + ) + + def _build_unversioned_content(self, source_dir: str, output_dir: str) -> None: + """Build unversioned content (langgraph-platform/ or labs/). + + Args: + source_dir: Source directory name (e.g., "langgraph-platform", "labs"). + output_dir: Output directory name (same as source_dir). + """ + src_path = self.src_dir / source_dir + if not src_path.exists(): + logger.warning("%s/ directory not found, skipping", source_dir) + return + + all_files = [ + file_path + for file_path in src_path.rglob("*") + if file_path.is_file() and not self._is_shared_file(file_path) + ] + + if not all_files: + logger.info("No files found in %s/ directory", source_dir) + return + + # Process files with progress bar + copied_count: int = 0 + skipped_count: int = 0 + + with tqdm( + total=len(all_files), + desc=f"Building {output_dir} files", + unit="file", + ncols=80, + bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}]", + ) as pbar: + for file_path in all_files: + # Calculate relative path from source directory + relative_path = file_path.relative_to(src_path) + # Build directly to output_dir/ + output_path = self.build_dir / output_dir / relative_path + + result = self._build_single_file( + file_path, + output_path, + "python", + pbar, + f"{output_dir}/{relative_path}", + ) + if result: + copied_count += 1 + else: + skipped_count += 1 + pbar.update(1) + + logger.info( + "✅ %s complete: %d files copied, %d files skipped", + output_dir, + copied_count, + skipped_count, + ) + + def _build_single_file( + self, + file_path: Path, + output_path: Path, + target_language: str, + pbar: tqdm, + display_path: str, + ) -> bool: + """Build a single file with progress bar integration. + + Args: + file_path: Path to the source file to be built. + output_path: Full output path for the file. + target_language: Target language for conditional blocks ("python" or "js"). + pbar: tqdm progress bar instance for updating the description. + display_path: Path to display in progress bar. + + Returns: + True if the file was copied, False if it was skipped. + """ + # Update progress bar description with current file + pbar.set_postfix_str(display_path) + + # Create output directory if needed + output_path.parent.mkdir(parents=True, exist_ok=True) + + # Handle special case for docs.yml files + if file_path.name == "docs.yml" and file_path.suffix.lower() in { + ".yml", + ".yaml", + }: + self._convert_yaml_to_json(file_path, output_path) + return True + # Copy other supported files + if file_path.suffix.lower() in self.copy_extensions: + # Handle markdown files with preprocessing + if file_path.suffix.lower() in {".md", ".mdx"}: + self._process_markdown_file(file_path, output_path, target_language) + return True + shutil.copy2(file_path, output_path) + return True + return False + + def _build_version_file_with_progress( + self, file_path: Path, version_dir: str, target_language: str, pbar: tqdm + ) -> bool: + """Build a single file for a specific version with progress bar integration. + + Args: + file_path: Path to the source file to be built. + version_dir: Directory name for this version (e.g., "python", "javascript"). + target_language: Target language for conditional blocks ("python" or "js"). + pbar: tqdm progress bar instance for updating the description. + + Returns: + True if the file was copied, False if it was skipped. + """ + relative_path = file_path.relative_to(self.src_dir) + # Add version prefix to the output path + output_path = self.build_dir / version_dir / relative_path + + # Update progress bar description with current file + pbar.set_postfix_str(f"{version_dir}/{relative_path}") + + # Create output directory if needed + output_path.parent.mkdir(parents=True, exist_ok=True) + + # Handle special case for docs.yml files + if file_path.name == "docs.yml" and file_path.suffix.lower() in { + ".yml", + ".yaml", + }: + self._convert_yaml_to_json(file_path, output_path) + return True + # Copy other supported files + if file_path.suffix.lower() in self.copy_extensions: + # Handle markdown files with preprocessing + if file_path.suffix.lower() in {".md", ".mdx"}: + self._process_markdown_file(file_path, output_path, target_language) + return True + shutil.copy2(file_path, output_path) + return True + return False + + def _is_shared_file(self, file_path: Path) -> bool: + """Check if a file should be shared between versions rather than duplicated. + + Args: + file_path: Path to check. + + Returns: + True if the file should be shared, False if it should be version-specific. + """ + # Shared files: docs.json, images directory, JavaScript files, snippets + relative_path = file_path.relative_to(self.src_dir) + + # docs.json should be shared + if file_path.name == "docs.json": + return True + + # Images directory should be shared + if "images" in relative_path.parts: + return True + + # Snippets directory should be shared + if "snippets" in relative_path.parts: + return True + + # JavaScript and CSS files should be shared (used for custom scripts/styles) + if file_path.suffix.lower() in {".js", ".css"}: + return True + + return False + + def _copy_shared_files(self) -> None: + """Copy files that should be shared between versions.""" + # Collect shared files + shared_files = [ + file_path + for file_path in self.src_dir.rglob("*") + if file_path.is_file() and self._is_shared_file(file_path) + ] + + if not shared_files: + logger.info("No shared files found") + return + + copied_count = 0 + for file_path in shared_files: + relative_path = file_path.relative_to(self.src_dir) + output_path = self.build_dir / relative_path + + # Create output directory if needed + output_path.parent.mkdir(parents=True, exist_ok=True) + + if file_path.suffix.lower() in self.copy_extensions: + shutil.copy2(file_path, output_path) + copied_count += 1 + + logger.info("✅ Shared files copied: %d files", copied_count) diff --git a/src/docs.json b/src/docs.json index 54f45dd0..131c57c9 100644 --- a/src/docs.json +++ b/src/docs.json @@ -23,25 +23,25 @@ } }, "styling": { - "eyebrows": "breadcrumbs" - }, + "eyebrows": "breadcrumbs" + }, "contextual": { "options": [ "copy", - "view", - { - "title": "llms.txt", - "description": "Open llms.txt for this site", - "icon": "file", - "href": "https://docs.langchain.com/llms.txt" - }, + "view", + { + "title": "llms.txt", + "description": "Open llms.txt for this site", + "icon": "file", + "href": "https://docs.langchain.com/llms.txt" + }, "chatgpt", "claude" ] }, "integrations": { "gtm": { - "tagId": "GTM-MBBX68ST" + "tagId": "GTM-MBBX68ST" } }, "head": [ @@ -91,97 +91,228 @@ "youtube": "https://www.youtube.com/@LangChain" } }, + "scripts": [ + "/hide-version-picker.js" + ], + "styles": [ + "/hide-version-picker.css" + ], "navigation": { - "global": { - "anchors": [ - { - "anchor": "Forum", - "icon": "comments", - "href": "https://forum.langchain.com/" - } - ] - }, - "dropdowns": [ + "global": { + "anchors": [ + { + "anchor": "Forum", + "icon": "comments", + "href": "https://forum.langchain.com/" + } + ] + }, + "versions": [ { - "dropdown": "LangGraph", - "icon": "/images/brand/langgraph-pill.svg", - "description": "Framework for building reliable agents and workflows", - "tabs": [ + "version": "Python", + "dropdowns": [ { - "tab": "Get started", - "groups": [ + "dropdown": "LangGraph", + "icon": "/images/brand/langgraph-pill.svg", + "description": "Framework for building reliable agents and workflows", + "tabs": [ { - "group": "Get started", - "pages": [ - "oss/overview", - "oss/quickstart", - "oss/run-an-agent", - "oss/prebuilt-vs-low-level" - ] - }, - { - "group": "Common architectures", - "pages": [ - "oss/agentic-architectures", - "oss/agentic-rag", - "oss/agent-supervisor", - "oss/sql-agent" + "tab": "Get started", + "groups": [ + { + "group": "Get started", + "pages": [ + "oss/python/overview", + "oss/python/quickstart", + "oss/python/run-an-agent", + "oss/python/prebuilt-vs-low-level" + ] + }, + { + "group": "Common architectures", + "pages": [ + "oss/python/agentic-architectures", + "oss/python/agentic-rag", + "oss/python/agent-supervisor", + "oss/python/sql-agent" + ] + }, + { + "group": "Additional resources", + "pages": [ + "oss/python/case-studies", + "oss/python/template-applications" + ] + } ] }, { - "group": "Additional resources", - "pages": [ - "oss/case-studies", - "oss/template-applications" - ] - } - ] - }, - { - "tab": "Build agents", - "groups": [ - { - "group": "Basic configuration", - "pages": [ - "oss/prebuilts" + "tab": "Build agents", + "groups": [ + { + "group": "Basic configuration", + "pages": [ + "oss/python/prebuilts" + ] + }, + { + "group": "Low-level configuration", + "pages": [ + "oss/python/why-langgraph", + "oss/python/1-build-basic-chatbot", + "oss/python/2-add-tools", + "oss/python/3-add-memory", + "oss/python/4-human-in-the-loop", + "oss/python/5-customize-state", + "oss/python/6-time-travel" + ] + }, + { + "group": "Components", + "pages": [ + "oss/python/models", + { + "group": "Tools", + "pages": [ + "oss/python/tools", + "oss/python/call-tools" + ] + }, + { + "group": "MCP", + "pages": [ + "oss/python/mcp", + "oss/python/use-mcp" + ] + }, + { + "group": "Multi-agent", + "pages": [ + "oss/python/multi-agent", + "oss/python/multi-agent-prebuilts", + "oss/python/multi-agent-custom" + ] + } + ] + } ] }, { - "group": "Low-level configuration", - "pages": [ - "oss/why-langgraph", - "oss/1-build-basic-chatbot", - "oss/2-add-tools", - "oss/3-add-memory", - "oss/4-human-in-the-loop", - "oss/5-customize-state", - "oss/6-time-travel" + "tab": "Agent runtime", + "groups": [ + { + "group": "Capabilities", + "pages": [ + "oss/python/persistence", + "oss/python/durable-execution", + { + "group": "Streaming", + "pages": [ + "oss/python/streaming", + "oss/python/use-streaming" + ] + }, + { + "group": "Human-in-the-loop", + "pages": [ + "oss/python/human-in-the-loop", + "oss/python/add-human-in-the-loop" + ] + }, + { + "group": "Time travel", + "pages": [ + "oss/python/time-travel", + "oss/python/use-time-travel" + ] + }, + { + "group": "Memory and context", + "pages": [ + "oss/python/memory", + "oss/python/context", + "oss/python/add-memory" + ] + }, + { + "group": "Subgraphs", + "pages": [ + "oss/python/subgraphs", + "oss/python/use-subgraphs" + ] + } + ] + }, + { + "group": "Run and debug", + "pages": [ + "oss/python/local-server", + "oss/python/ui", + "oss/python/trace-agent", + "oss/python/evals" + ] + }, + { + "group": "LangGraph APIs", + "pages": [ + { + "group": "Graph API", + "pages": [ + "oss/python/graph-api", + "oss/python/use-graph-api" + ] + }, + { + "group": "Functional API", + "pages": [ + "oss/python/functional-api", + "oss/python/use-functional-api" + ] + }, + "oss/python/pregel" + ] + } ] }, { - "group": "Components", - "pages": [ - "oss/models", + "tab": "Reference", + "groups": [ { - "group": "Tools", + "group": "LangGraph reference", "pages": [ - "oss/tools", - "oss/call-tools" + "oss/python/reference/overview", + "oss/python/reference/graphs", + "oss/python/reference/functional-api", + "oss/python/reference/pregel", + "oss/python/reference/checkpointers", + "oss/python/reference/storage", + "oss/python/reference/caching", + "oss/python/reference/types", + "oss/python/reference/runtime", + "oss/python/reference/config", + "oss/python/reference/errors", + "oss/python/reference/constants", + "oss/python/reference/channels" ] }, { - "group": "MCP", + "group": "Prebuilt reference", "pages": [ - "oss/mcp", - "oss/use-mcp" + "oss/python/reference/agents", + "oss/python/reference/supervisor", + "oss/python/reference/swarm", + "oss/python/reference/mcp" ] }, { - "group": "Multi-agent", + "group": "Error troubleshooting", "pages": [ - "oss/multi-agent", - "oss/multi-agent-prebuilts", - "oss/multi-agent-custom" + "oss/python/common-errors", + "oss/python/GRAPH_RECURSION_LIMIT", + "oss/python/INVALID_CHAT_HISTORY", + "oss/python/INVALID_CONCURRENT_GRAPH_UPDATE", + "oss/python/INVALID_GRAPH_NODE_RETURN_VALUE", + "oss/python/MULTIPLE_SUBGRAPHS" ] } ] @@ -189,121 +320,266 @@ ] }, { - "tab": "Agent runtime", - "groups": [ + "dropdown": "LangGraph Platform", + "icon": "/images/brand/langgraph-platform-pill.svg", + "description": "Platform for building and deploying AI agents", + "tabs": [ { - "group": "Capabilities", - "pages": [ - "oss/persistence", - "oss/durable-execution", + "tab": "Get started", + "groups": [ + { + "group": "Overview", + "pages": [ + "langgraph-platform/index", + { + "group": "Components", + "pages": [ + "langgraph-platform/components", + "langgraph-platform/langgraph-server", + "langgraph-platform/data-plane", + "langgraph-platform/control-plane" + ] + }, + "langgraph-platform/application-structure" + ] + }, { - "group": "Streaming", + "group": "Quickstarts", "pages": [ - "oss/streaming", - "oss/use-streaming" + "langgraph-platform/local-server", + "langgraph-platform/deployment-quickstart", + "langgraph-platform/quick-start-studio" ] }, { - "group": "Human-in-the-loop", + "group": "Plans and deployment", + "pages": [ + "langgraph-platform/plans" + ] + } + ] + }, + { + "tab": "Build", + "groups": [ + { + "group": "Build an app with the LangGraph basics", "pages": [ - "oss/human-in-the-loop", - "oss/add-human-in-the-loop" + "langgraph-platform/langgraph-basics/why-langgraph", + "langgraph-platform/langgraph-basics/1-build-basic-chatbot", + "langgraph-platform/langgraph-basics/2-add-tools", + "langgraph-platform/langgraph-basics/3-add-memory", + "langgraph-platform/langgraph-basics/4-human-in-the-loop", + "langgraph-platform/langgraph-basics/5-customize-state", + "langgraph-platform/langgraph-basics/6-time-travel" ] }, { - "group": "Time travel", + "group": "Data models", "pages": [ - "oss/time-travel", - "oss/use-time-travel" + { + "group": "Assistants", + "pages": [ + "langgraph-platform/assistants", + "langgraph-platform/configuration-cloud", + "langgraph-platform/use-threads" + ] + }, + { + "group": "Runs", + "pages": [ + "langgraph-platform/background-run", + "langgraph-platform/same-thread", + "langgraph-platform/cron-jobs", + "langgraph-platform/stateless-runs", + "langgraph-platform/configurable-headers" + ] + } ] }, { - "group": "Memory and context", + "group": "Core capabilities", "pages": [ - "oss/memory", - "oss/context", - "oss/add-memory" + "langgraph-platform/streaming", + "langgraph-platform/add-human-in-the-loop", + "langgraph-platform/human-in-the-loop-time-travel", + "langgraph-platform/server-mcp", + "langgraph-platform/use-webhooks", + { + "group": "Double-texting", + "pages": [ + "langgraph-platform/double-texting", + "langgraph-platform/interrupt-concurrent", + "langgraph-platform/rollback-concurrent", + "langgraph-platform/reject-concurrent", + "langgraph-platform/enqueue-concurrent" + ] + } ] }, { - "group": "Subgraphs", + "group": "LangGraph Studio", "pages": [ - "oss/subgraphs", - "oss/use-subgraphs" + "langgraph-platform/langgraph-studio", + "langgraph-platform/invoke-studio", + "langgraph-platform/manage-assistants-studio", + "langgraph-platform/threads-studio", + "langgraph-platform/iterate-graph-studio", + "langgraph-platform/run-evals-studio", + "langgraph-platform/clone-traces-studio", + "langgraph-platform/datasets-studio", + "langgraph-platform/troubleshooting-studio" ] } ] }, { - "group": "Run and debug", - "pages": [ - "oss/local-server", - "oss/ui", - "oss/trace-agent", - "oss/evals" + "tab": "Deploy", + "groups": [ + { + "group": "Overview", + "pages": [ + "langgraph-platform/deployment-options", + "langgraph-platform/cloud", + "langgraph-platform/hybrid", + "langgraph-platform/self-hosted" + ] + }, + { + "group": "Guides for deployment", + "pages": [ + "langgraph-platform/deploy-to-cloud", + "langgraph-platform/deploy-hybrid", + "langgraph-platform/deploy-self-hosted-full-platform", + "langgraph-platform/deploy-data-plane-only", + "langgraph-platform/use-remote-graph" + ] + }, + { + "group": "Configure your application for deployment", + "pages": [ + "langgraph-platform/setup-app-requirements-txt", + "langgraph-platform/setup-pyproject", + "langgraph-platform/setup-javascript", + "langgraph-platform/custom-docker", + "langgraph-platform/graph-rebuild", + "langgraph-platform/langgraph-cli", + "langgraph-platform/sdk", + "langgraph-platform/egress-metrics-metadata" + ] + } ] }, { - "group": "LangGraph APIs", - "pages": [ + "tab": "Manage", + "groups": [ + { + "group": "Authentication & access control", + "pages": [ + "langgraph-platform/auth", + "langgraph-platform/custom-auth", + "langgraph-platform/set-up-custom-auth", + "langgraph-platform/resource-auth", + "langgraph-platform/add-auth-server", + "langgraph-platform/openapi-security" + ] + }, + { + "group": "Scalability & resilience", + "pages": [ + "langgraph-platform/scalability-and-resilience" + ] + }, { - "group": "Graph API", + "group": "Server customization", "pages": [ - "oss/graph-api", - "oss/use-graph-api" + "langgraph-platform/custom-lifespan", + "langgraph-platform/custom-middleware", + "langgraph-platform/custom-routes" ] }, { - "group": "Functional API", + "group": "Data management", "pages": [ - "oss/functional-api", - "oss/use-functional-api" + "langgraph-platform/data-storage-and-privacy", + "langgraph-platform/semantic-search", + "langgraph-platform/configure-ttl" ] }, - "oss/pregel" + { + "group": "Tutorials", + "pages": [ + "langgraph-platform/autogen-integration", + "langgraph-platform/use-stream-react", + "langgraph-platform/generative-ui-react" + ] + } + ] + }, + { + "tab": "Reference", + "pages": [ + "langgraph-platform/reference-overview", + "langgraph-platform/server-api-ref", + "langgraph-platform/langgraph-server-changelog", + "langgraph-platform/api-ref-control-plane", + "langgraph-platform/cli", + "langgraph-platform/env-var", + "langgraph-platform/python-sdk", + "langgraph-platform/js-ts-sdk", + "langgraph-platform/remote-graph", + "langgraph-platform/faq" ] } ] }, { - "tab": "Reference", - "groups": [ + "dropdown": "LangChain Labs", + "icon": "/images/brand/langchain-labs-pill.svg", + "description": "Experimental AI products from LangChain", + "tabs": [ { - "group": "LangGraph reference", + "tab": "Overview", "pages": [ - "oss/reference/overview", - "oss/reference/graphs", - "oss/reference/functional-api", - "oss/reference/pregel", - "oss/reference/checkpointers", - "oss/reference/storage", - "oss/reference/caching", - "oss/reference/types", - "oss/reference/runtime", - "oss/reference/config", - "oss/reference/errors", - "oss/reference/constants", - "oss/reference/channels" + "labs/index" ] }, { - "group": "Prebuilt reference", + "tab": "Open SWE", "pages": [ - "oss/reference/agents", - "oss/reference/supervisor", - "oss/reference/swarm", - "oss/reference/mcp" - ] - }, - { - "group": "Error troubleshooting", - "pages": [ - "oss/common-errors", - "oss/GRAPH_RECURSION_LIMIT", - "oss/INVALID_CHAT_HISTORY", - "oss/INVALID_CONCURRENT_GRAPH_UPDATE", - "oss/INVALID_GRAPH_NODE_RETURN_VALUE", - "oss/MULTIPLE_SUBGRAPHS" + { + "group": "Get Started", + "pages": [ + "labs/swe/index" + ] + }, + { + "group": "Usage", + "pages": [ + "labs/swe/usage/intro", + "labs/swe/usage/ui", + "labs/swe/usage/github", + "labs/swe/usage/best-practices", + "labs/swe/usage/custom-rules", + "labs/swe/usage/examples" + ] + }, + { + "group": "Development Setup", + "pages": [ + "labs/swe/setup/intro", + "labs/swe/setup/development", + "labs/swe/setup/authentication", + "labs/swe/setup/monorepo", + "labs/swe/setup/ci" + ] + }, + { + "group": "FAQ", + "pages": [ + "labs/swe/faq" + ] + } ] } ] @@ -311,175 +587,411 @@ ] }, { - "dropdown": "LangGraph Platform", - "icon": "/images/brand/langgraph-platform-pill.svg", - "description": "Platform for building and deploying AI agents", - "tabs": [ + "version": "JavaScript", + "dropdowns": [ { - "tab": "Get started", - "groups": [ + "dropdown": "LangGraph", + "icon": "/images/brand/langgraph-pill.svg", + "description": "Framework for building reliable agents and workflows", + "tabs": [ { - "group": "Overview", - "pages": [ - "langgraph-platform/index", + "tab": "Get started", + "groups": [ { - "group": "Components", + "group": "Get started", "pages": [ - "langgraph-platform/components", - "langgraph-platform/langgraph-server", - "langgraph-platform/data-plane", - "langgraph-platform/control-plane" + "oss/javascript/overview", + "oss/javascript/quickstart", + "oss/javascript/run-an-agent", + "oss/javascript/prebuilt-vs-low-level" ] }, - "langgraph-platform/application-structure" - ] - }, - { - "group": "Quickstarts", - "pages": [ - "langgraph-platform/local-server", - "langgraph-platform/deployment-quickstart", - "langgraph-platform/quick-start-studio" - ] - }, - { - "group": "Plans and deployment", - "pages": [ - "langgraph-platform/plans" - ] - } - ] - }, - { - "tab": "Build", - "groups": [ - { - "group": "Build an app with the LangGraph basics", - "pages": [ - "langgraph-platform/langgraph-basics/why-langgraph", - "langgraph-platform/langgraph-basics/1-build-basic-chatbot", - "langgraph-platform/langgraph-basics/2-add-tools", - "langgraph-platform/langgraph-basics/3-add-memory", - "langgraph-platform/langgraph-basics/4-human-in-the-loop", - "langgraph-platform/langgraph-basics/5-customize-state", - "langgraph-platform/langgraph-basics/6-time-travel" + { + "group": "Common architectures", + "pages": [ + "oss/javascript/agentic-architectures", + "oss/javascript/agentic-rag", + "oss/javascript/agent-supervisor", + "oss/javascript/sql-agent" + ] + }, + { + "group": "Additional resources", + "pages": [ + "oss/javascript/case-studies", + "oss/javascript/template-applications" + ] + } ] }, { - "group": "Data models", - "pages": [ + "tab": "Build agents", + "groups": [ { - "group": "Assistants", + "group": "Basic configuration", "pages": [ - "langgraph-platform/assistants", - "langgraph-platform/configuration-cloud", - "langgraph-platform/use-threads" + "oss/javascript/prebuilts" ] }, { - "group": "Runs", + "group": "Low-level configuration", "pages": [ - "langgraph-platform/background-run", - "langgraph-platform/same-thread", - "langgraph-platform/cron-jobs", - "langgraph-platform/stateless-runs", - "langgraph-platform/configurable-headers" + "oss/javascript/why-langgraph", + "oss/javascript/1-build-basic-chatbot", + "oss/javascript/2-add-tools", + "oss/javascript/3-add-memory", + "oss/javascript/4-human-in-the-loop", + "oss/javascript/5-customize-state", + "oss/javascript/6-time-travel" + ] + }, + { + "group": "Components", + "pages": [ + "oss/javascript/models", + { + "group": "Tools", + "pages": [ + "oss/javascript/tools", + "oss/javascript/call-tools" + ] + }, + { + "group": "MCP", + "pages": [ + "oss/javascript/mcp", + "oss/javascript/use-mcp" + ] + }, + { + "group": "Multi-agent", + "pages": [ + "oss/javascript/multi-agent", + "oss/javascript/multi-agent-prebuilts", + "oss/javascript/multi-agent-custom" + ] + } ] } ] }, { - "group": "Core capabilities", - "pages": [ - "langgraph-platform/streaming", - "langgraph-platform/add-human-in-the-loop", - "langgraph-platform/human-in-the-loop-time-travel", - "langgraph-platform/server-mcp", - "langgraph-platform/use-webhooks", + "tab": "Agent runtime", + "groups": [ + { + "group": "Capabilities", + "pages": [ + "oss/javascript/persistence", + "oss/javascript/durable-execution", + { + "group": "Streaming", + "pages": [ + "oss/javascript/streaming", + "oss/javascript/use-streaming" + ] + }, + { + "group": "Human-in-the-loop", + "pages": [ + "oss/javascript/human-in-the-loop", + "oss/javascript/add-human-in-the-loop" + ] + }, + { + "group": "Time travel", + "pages": [ + "oss/javascript/time-travel", + "oss/javascript/use-time-travel" + ] + }, + { + "group": "Memory and context", + "pages": [ + "oss/javascript/memory", + "oss/javascript/context", + "oss/javascript/add-memory" + ] + }, + { + "group": "Subgraphs", + "pages": [ + "oss/javascript/subgraphs", + "oss/javascript/use-subgraphs" + ] + } + ] + }, { - "group": "Double-texting", + "group": "Run and debug", "pages": [ - "langgraph-platform/double-texting", - "langgraph-platform/interrupt-concurrent", - "langgraph-platform/rollback-concurrent", - "langgraph-platform/reject-concurrent", - "langgraph-platform/enqueue-concurrent" + "oss/javascript/local-server", + "oss/javascript/ui", + "oss/javascript/trace-agent", + "oss/javascript/evals" + ] + }, + { + "group": "LangGraph APIs", + "pages": [ + { + "group": "Graph API", + "pages": [ + "oss/javascript/graph-api", + "oss/javascript/use-graph-api" + ] + }, + { + "group": "Functional API", + "pages": [ + "oss/javascript/functional-api", + "oss/javascript/use-functional-api" + ] + }, + "oss/javascript/pregel" ] } ] }, { - "group": "LangGraph Studio", - "pages": [ - "langgraph-platform/langgraph-studio", - "langgraph-platform/invoke-studio", - "langgraph-platform/manage-assistants-studio", - "langgraph-platform/threads-studio", - "langgraph-platform/iterate-graph-studio", - "langgraph-platform/run-evals-studio", - "langgraph-platform/clone-traces-studio", - "langgraph-platform/datasets-studio", - "langgraph-platform/troubleshooting-studio" + "tab": "Reference", + "groups": [ + { + "group": "LangGraph reference", + "pages": [ + "oss/javascript/reference/overview", + "oss/javascript/reference/graphs", + "oss/javascript/reference/functional-api", + "oss/javascript/reference/pregel", + "oss/javascript/reference/checkpointers", + "oss/javascript/reference/storage", + "oss/javascript/reference/caching", + "oss/javascript/reference/types", + "oss/javascript/reference/runtime", + "oss/javascript/reference/config", + "oss/javascript/reference/errors", + "oss/javascript/reference/constants", + "oss/javascript/reference/channels" + ] + }, + { + "group": "Prebuilt reference", + "pages": [ + "oss/javascript/reference/agents", + "oss/javascript/reference/supervisor", + "oss/javascript/reference/swarm", + "oss/javascript/reference/mcp" + ] + }, + { + "group": "Error troubleshooting", + "pages": [ + "oss/javascript/common-errors", + "oss/javascript/GRAPH_RECURSION_LIMIT", + "oss/javascript/INVALID_CHAT_HISTORY", + "oss/javascript/INVALID_CONCURRENT_GRAPH_UPDATE", + "oss/javascript/INVALID_GRAPH_NODE_RETURN_VALUE", + "oss/javascript/MULTIPLE_SUBGRAPHS" + ] + } ] } ] }, { - "tab": "Deploy", - "groups": [ + "dropdown": "LangGraph Platform", + "icon": "/images/brand/langgraph-platform-pill.svg", + "description": "Platform for building and deploying AI agents", + "tabs": [ { - "group": "Overview", - "pages": [ - "langgraph-platform/deployment-options", - "langgraph-platform/cloud", - "langgraph-platform/hybrid", - "langgraph-platform/self-hosted" + "tab": "Get started", + "groups": [ + { + "group": "Overview", + "pages": [ + "langgraph-platform/index", + { + "group": "Components", + "pages": [ + "langgraph-platform/components", + "langgraph-platform/langgraph-server", + "langgraph-platform/data-plane", + "langgraph-platform/control-plane" + ] + }, + "langgraph-platform/application-structure" + ] + }, + { + "group": "Quickstarts", + "pages": [ + "langgraph-platform/local-server", + "langgraph-platform/deployment-quickstart", + "langgraph-platform/quick-start-studio" + ] + }, + { + "group": "Plans and deployment", + "pages": [ + "langgraph-platform/plans" + ] + } ] }, { - "group": "Guides for deployment", - "pages": [ - "langgraph-platform/deploy-to-cloud", - "langgraph-platform/deploy-hybrid", - "langgraph-platform/deploy-self-hosted-full-platform", - "langgraph-platform/deploy-standalone-server", - "langgraph-platform/use-remote-graph" + "tab": "Build", + "groups": [ + { + "group": "Build an app with the LangGraph basics", + "pages": [ + "langgraph-platform/langgraph-basics/why-langgraph", + "langgraph-platform/langgraph-basics/1-build-basic-chatbot", + "langgraph-platform/langgraph-basics/2-add-tools", + "langgraph-platform/langgraph-basics/3-add-memory", + "langgraph-platform/langgraph-basics/4-human-in-the-loop", + "langgraph-platform/langgraph-basics/5-customize-state", + "langgraph-platform/langgraph-basics/6-time-travel" + ] + }, + { + "group": "Data models", + "pages": [ + { + "group": "Assistants", + "pages": [ + "langgraph-platform/assistants", + "langgraph-platform/configuration-cloud", + "langgraph-platform/use-threads" + ] + }, + { + "group": "Runs", + "pages": [ + "langgraph-platform/background-run", + "langgraph-platform/same-thread", + "langgraph-platform/cron-jobs", + "langgraph-platform/stateless-runs", + "langgraph-platform/configurable-headers" + ] + } + ] + }, + { + "group": "Core capabilities", + "pages": [ + "langgraph-platform/streaming", + "langgraph-platform/add-human-in-the-loop", + "langgraph-platform/human-in-the-loop-time-travel", + "langgraph-platform/server-mcp", + "langgraph-platform/use-webhooks", + { + "group": "Double-texting", + "pages": [ + "langgraph-platform/double-texting", + "langgraph-platform/interrupt-concurrent", + "langgraph-platform/rollback-concurrent", + "langgraph-platform/reject-concurrent", + "langgraph-platform/enqueue-concurrent" + ] + } + ] + }, + { + "group": "LangGraph Studio", + "pages": [ + "langgraph-platform/langgraph-studio", + "langgraph-platform/invoke-studio", + "langgraph-platform/manage-assistants-studio", + "langgraph-platform/threads-studio", + "langgraph-platform/iterate-graph-studio", + "langgraph-platform/run-evals-studio", + "langgraph-platform/clone-traces-studio", + "langgraph-platform/datasets-studio", + "langgraph-platform/troubleshooting-studio" + ] + } ] }, { - "group": "Configure your application for deployment", - "pages": [ - "langgraph-platform/setup-app-requirements-txt", - "langgraph-platform/setup-pyproject", - "langgraph-platform/setup-javascript", - "langgraph-platform/custom-docker", - "langgraph-platform/graph-rebuild", - "langgraph-platform/langgraph-cli", - "langgraph-platform/sdk", - "langgraph-platform/egress-metrics-metadata" - ] - } - ] - }, - { - "tab": "Manage", - "groups": [ - - { - "group": "Authentication & access control", - "pages": [ - "langgraph-platform/auth", - "langgraph-platform/custom-auth", - "langgraph-platform/set-up-custom-auth", - "langgraph-platform/resource-auth", - "langgraph-platform/add-auth-server", - "langgraph-platform/openapi-security" + "tab": "Deploy", + "groups": [ + { + "group": "Overview", + "pages": [ + "langgraph-platform/deployment-options", + "langgraph-platform/cloud", + "langgraph-platform/hybrid", + "langgraph-platform/self-hosted" + ] + }, + { + "group": "Guides for deployment", + "pages": [ + "langgraph-platform/deploy-to-cloud", + "langgraph-platform/deploy-hybrid", + "langgraph-platform/deploy-self-hosted-full-platform", + "langgraph-platform/deploy-data-plane-only", + "langgraph-platform/use-remote-graph" + ] + }, + { + "group": "Configure your application for deployment", + "pages": [ + "langgraph-platform/setup-app-requirements-txt", + "langgraph-platform/setup-pyproject", + "langgraph-platform/setup-javascript", + "langgraph-platform/custom-docker", + "langgraph-platform/graph-rebuild", + "langgraph-platform/langgraph-cli", + "langgraph-platform/sdk", + "langgraph-platform/egress-metrics-metadata" + ] + } ] }, { - "group": "Scalability & resilience", - "pages": [ - "langgraph-platform/scalability-and-resilience" + "tab": "Manage", + "groups": [ + { + "group": "Authentication & access control", + "pages": [ + "langgraph-platform/auth", + "langgraph-platform/custom-auth", + "langgraph-platform/set-up-custom-auth", + "langgraph-platform/resource-auth", + "langgraph-platform/add-auth-server", + "langgraph-platform/openapi-security" + ] + }, + { + "group": "Scalability & resilience", + "pages": [ + "langgraph-platform/scalability-and-resilience" + ] + }, + { + "group": "Server customization", + "pages": [ + "langgraph-platform/custom-lifespan", + "langgraph-platform/custom-middleware", + "langgraph-platform/custom-routes" + ] + }, + { + "group": "Data management", + "pages": [ + "langgraph-platform/data-storage-and-privacy", + "langgraph-platform/semantic-search", + "langgraph-platform/configure-ttl" + ] + }, + { + "group": "Tutorials", + "pages": [ + "langgraph-platform/autogen-integration", + "langgraph-platform/use-stream-react", + "langgraph-platform/generative-ui-react" + ] + } ] }, { @@ -499,75 +1011,69 @@ ] }, { - "group": "Tutorials", + "tab": "Reference", "pages": [ - "langgraph-platform/autogen-integration", - "langgraph-platform/use-stream-react", - "langgraph-platform/generative-ui-react" + "langgraph-platform/reference-overview", + "langgraph-platform/server-api-ref", + "langgraph-platform/langgraph-server-changelog", + "langgraph-platform/api-ref-control-plane", + "langgraph-platform/cli", + "langgraph-platform/env-var", + "langgraph-platform/python-sdk", + "langgraph-platform/js-ts-sdk", + "langgraph-platform/remote-graph", + "langgraph-platform/faq" ] } ] }, { - "tab": "Reference", - "pages": [ - "langgraph-platform/reference-overview", - "langgraph-platform/server-api-ref", - "langgraph-platform/langgraph-server-changelog", - "langgraph-platform/api-ref-control-plane", - "langgraph-platform/cli", - "langgraph-platform/env-var", - "langgraph-platform/python-sdk", - "langgraph-platform/js-ts-sdk", - "langgraph-platform/remote-graph", - "langgraph-platform/faq" - ] - } - ] - }, - { - "dropdown": "LangChain Labs", - "icon": "/images/brand/langchain-labs-pill.svg", - "description": "Experimental AI products from LangChain", - "tabs": [ - { - "tab": "Overview", - "pages": ["labs/index"] - }, - { - "tab": "Open SWE", - "pages": [ + "dropdown": "LangChain Labs", + "icon": "/images/brand/langchain-labs-pill.svg", + "description": "Experimental AI products from LangChain", + "tabs": [ { - "group": "Get Started", + "tab": "Overview", "pages": [ - "labs/swe/index" + "labs/index" ] }, { - "group": "Usage", + "tab": "Open SWE", "pages": [ - "labs/swe/usage/intro", - "labs/swe/usage/ui", - "labs/swe/usage/github", - "labs/swe/usage/best-practices", - "labs/swe/usage/custom-rules", - "labs/swe/usage/examples" - ] - }, - { - "group": "Development Setup", - "pages": [ - "labs/swe/setup/intro", - "labs/swe/setup/development", - "labs/swe/setup/authentication", - "labs/swe/setup/monorepo", - "labs/swe/setup/ci" - ] - }, - { - "group": "FAQ", - "pages": [ - "labs/swe/faq" + { + "group": "Get Started", + "pages": [ + "labs/swe/index" + ] + }, + { + "group": "Usage", + "pages": [ + "labs/swe/usage/intro", + "labs/swe/usage/ui", + "labs/swe/usage/github", + "labs/swe/usage/best-practices", + "labs/swe/usage/custom-rules", + "labs/swe/usage/examples" + ] + }, + { + "group": "Development Setup", + "pages": [ + "labs/swe/setup/intro", + "labs/swe/setup/development", + "labs/swe/setup/authentication", + "labs/swe/setup/monorepo", + "labs/swe/setup/ci" + ] + }, + { + "group": "FAQ", + "pages": [ + "labs/swe/faq" + ] + } ] } ] @@ -576,4 +1082,4 @@ } ] } -} +} \ No newline at end of file diff --git a/src/hide-version-picker.css b/src/hide-version-picker.css new file mode 100644 index 00000000..df1036f8 --- /dev/null +++ b/src/hide-version-picker.css @@ -0,0 +1,27 @@ +/** + * Hide version picker on unversioned content pages. + * + * This CSS hides the Mintlify version picker when users are viewing + * LangGraph Platform or LangChain Labs pages, since these sections + * have the same content regardless of Python/JavaScript version. + * + * Two-layer approach: + * 1. Primary: Match buttons marked by our JavaScript + * 2. Fallback: Match by Mintlify's specific styling + */ + +/* Primary selector: Match version picker buttons on unversioned pages */ +.hide-version-picker button.version-picker-button { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + pointer-events: none !important; +} + +/* Fallback: Match by Mintlify's specific styling */ +.hide-version-picker button[aria-haspopup="menu"][class*="text-xs"][class*="gap-1.5"] { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + pointer-events: none !important; +} \ No newline at end of file diff --git a/src/hide-version-picker.js b/src/hide-version-picker.js new file mode 100644 index 00000000..57384d7b --- /dev/null +++ b/src/hide-version-picker.js @@ -0,0 +1,51 @@ +/** + * Minimal script to add CSS classes for version picker hiding. + * + * This script adds CSS classes to the body element based on URL, + * and to version picker buttons based on their content. + */ +(function() { + 'use strict'; + + function addVersionPickerClasses() { + const currentPath = window.location.pathname; + const body = document.body; + + // Remove existing classes + body.classList.remove('hide-version-picker'); + + // Add appropriate class based on URL + if (currentPath.includes('/langgraph-platform/') || currentPath.includes('/langgraph-platform')) { + body.classList.add('hide-version-picker'); + } else if (currentPath.match(/\/labs(?:\/|$)/)) { + body.classList.add('hide-version-picker'); + } + + // Add classes to version picker buttons + document.querySelectorAll('button[aria-haspopup="menu"]').forEach(button => { + const buttonText = button.textContent.trim().toLowerCase(); + if (buttonText === 'python' || buttonText === 'javascript') { + button.classList.add('version-picker-button'); + } + }); + } + + // Run immediately + addVersionPickerClasses(); + + // Run on page load + document.addEventListener('DOMContentLoaded', addVersionPickerClasses); + + // Run on navigation + window.addEventListener('popstate', addVersionPickerClasses); + + // Watch for URL changes (SPA navigation) + let lastUrl = location.href; + new MutationObserver(() => { + const url = location.href; + if (url !== lastUrl) { + lastUrl = url; + addVersionPickerClasses(); + } + }).observe(document, { subtree: true, childList: true }); +})(); \ No newline at end of file diff --git a/tests/unit_tests/test_builder.py b/tests/unit_tests/test_builder.py index e90506c3..63fe6080 100644 --- a/tests/unit_tests/test_builder.py +++ b/tests/unit_tests/test_builder.py @@ -36,6 +36,7 @@ def test_builder_initialization() -> None: ".yml", ".yaml", ".css", + ".js", } @@ -49,58 +50,145 @@ def test_build_all_empty_directory() -> None: builder.build_all() assert not fs.list_build_files() - -def test_build_all_supported_files() -> None: - """Test building all supported file types. - - Verifies that the builder correctly copies all supported file types - while maintaining directory structure. - """ - files = [ - File(path="index.mdx", content="# Welcome"), - File(path="config.json", content='{"name": "test"}'), - File(path="images/logo.png", bytes=b"PNG_DATA"), - File(path="guides/setup.md", content="# Setup Guide"), - ] - - with file_system(files) as fs: - builder = DocumentationBuilder(fs.src_dir, fs.build_dir) - builder.build_all() - - # Verify all files were copied - build_files = fs.list_build_files() - assert len(build_files) == 4 - assert Path("index.mdx") in build_files - assert Path("config.json") in build_files - assert Path("images/logo.png") in build_files - assert Path("guides/setup.mdx") in build_files - - -def test_build_all_unsupported_files() -> None: - """Test building with unsupported file types. - - Verifies that the builder skips unsupported file types. - """ - files = [ - File( - path="index.mdx", - content="# Welcome", - ), - File( - path="ignored.txt", - content="This should be ignored", - ), - ] - - with file_system(files) as fs: - builder = DocumentationBuilder(fs.src_dir, fs.build_dir) - builder.build_all() - - # Verify only supported files were copied - build_files = fs.list_build_files() - assert len(build_files) == 1 - assert Path("index.mdx") in build_files - assert not fs.build_file_exists("ignored.txt") + def test_build_all_supported_files() -> None: + """Test building all supported file types. + + Verifies that the builder correctly copies all supported file types + while maintaining directory structure. + """ + files = [ + # LangGraph (oss) files - both Python and JavaScript versions + File(path="oss/index.mdx", content="# Welcome"), + File(path="oss/config.json", content='{"name": "test"}'), + File(path="oss/guides/setup.md", content="# Setup Guide"), + # LangGraph Platform files + File(path="langgraph-platform/index.mdx", content="# Platform"), + File(path="langgraph-platform/guide.md", content="# Guide"), + # LangChain Labs files + File(path="labs/index.mdx", content="# Labs"), + # Shared files + File(path="images/logo.png", bytes=b"PNG_DATA"), + File(path="docs.json", content='{"name": "test"}'), + ] + + with file_system(files) as fs: + builder = DocumentationBuilder(fs.src_dir, fs.build_dir) + builder.build_all() + + # Verify all files were copied with correct structure + build_files = set(str(p) for p in fs.list_build_files()) + + # Python version of LangGraph files + assert "oss/python/index.mdx" in build_files + assert "oss/python/config.json" in build_files + assert "oss/python/guides/setup.md" in build_files + + # JavaScript version of LangGraph files + assert "oss/javascript/index.mdx" in build_files + assert "oss/javascript/config.json" in build_files + assert "oss/javascript/guides/setup.md" in build_files + + # LangGraph Platform files + assert "langgraph-platform/index.mdx" in build_files + assert "langgraph-platform/guide.md" in build_files + + # LangChain Labs files + assert "labs/index.mdx" in build_files + + # Shared files + assert "images/logo.png" in build_files + assert "docs.json" in build_files + + # Total number of files should be: + # - 3 files * 2 versions (Python/JavaScript) for LangGraph + # - 2 files for Platform + # - 1 file for Labs + # - 2 shared files + assert len(build_files) == 11 + + def test_build_all_unsupported_files() -> None: + """Test building with unsupported file types. + + Verifies that the builder skips unsupported file types. + """ + files = [ + # LangGraph files with supported and unsupported types + File( + path="oss/index.mdx", + content="# Welcome", + ), + File( + path="oss/ignored.txt", + content="This should be ignored", + ), + File( + path="oss/data.csv", + content="col1,col2\n1,2", + ), + # Platform files with supported and unsupported types + File( + path="langgraph-platform/guide.md", + content="# Guide", + ), + File( + path="langgraph-platform/ignored.txt", + content="This should be ignored", + ), + # Labs files with supported and unsupported types + File( + path="labs/index.mdx", + content="# Labs", + ), + File( + path="labs/data.csv", + content="col1,col2\n1,2", + ), + # Shared files with supported and unsupported types + File( + path="images/logo.png", + bytes=b"PNG_DATA", + ), + File( + path="ignored.txt", + content="This should be ignored", + ), + ] + + with file_system(files) as fs: + builder = DocumentationBuilder(fs.src_dir, fs.build_dir) + builder.build_all() + + # Verify only supported files were copied + build_files = set(str(p) for p in fs.list_build_files()) + + # Python version of LangGraph files (only .mdx) + assert "oss/python/index.mdx" in build_files + assert "oss/python/ignored.txt" not in build_files + assert "oss/python/data.csv" not in build_files + + # JavaScript version of LangGraph files (only .mdx) + assert "oss/javascript/index.mdx" in build_files + assert "oss/javascript/ignored.txt" not in build_files + assert "oss/javascript/data.csv" not in build_files + + # Platform files (only .md) + assert "langgraph-platform/guide.md" in build_files + assert "langgraph-platform/ignored.txt" not in build_files + + # Labs files (only .mdx) + assert "labs/index.mdx" in build_files + assert "labs/data.csv" not in build_files + + # Shared files (only .png) + assert "images/logo.png" in build_files + assert "ignored.txt" not in build_files + + # Total number of files should be: + # - 1 file * 2 versions (Python/JavaScript) for LangGraph + # - 1 file for Platform + # - 1 file for Labs + # - 1 shared file + assert len(build_files) == 4 def test_build_single_file() -> None: