diff --git a/pipeline/core/builder.py b/pipeline/core/builder.py index 88771de0..3ef8abe2 100644 --- a/pipeline/core/builder.py +++ b/pipeline/core/builder.py @@ -1,15 +1,24 @@ """Documentation builder implementation.""" +import copy import json import logging import re import shutil from pathlib import Path +from typing import cast import yaml from tqdm import tqdm -from pipeline.preprocessors import preprocess_markdown +from pipeline.preprocessors import has_conditional_blocks, preprocess_markdown +from pipeline.tools.mintlify import ( + MintlifyConfig, + NavigationDropdown, + NavigationGroup, + NavigationTab, + NavigationVersion, +) logger = logging.getLogger(__name__) @@ -85,53 +94,80 @@ def build_all(self) -> None: shutil.rmtree(self.build_dir) self.build_dir.mkdir(parents=True, exist_ok=True) - # Build LangGraph versioned content (oss/ -> oss/python/ and oss/javascript/) - logger.info("Building LangGraph Python version...") - self._build_langgraph_version("oss/python", "python") + # Get all top-level directories in the source directory + top_level_dirs = set() + for item in self.src_dir.iterdir(): + if item.is_dir(): + top_level_dirs.add(item.name) - logger.info("Building LangGraph JavaScript version...") - self._build_langgraph_version("oss/javascript", "js") - - # Build unversioned content (same content regardless of version) - logger.info("Building LangGraph Platform content...") - self._build_unversioned_content("langgraph-platform", "langgraph-platform") + # Get unique list of all conditional files and extract top-level directories + conditional_dirs = set() + for file_path in self._get_conditional_files(): + relative_path = file_path.relative_to(self.src_dir) + if relative_path.parts: + top_level_dir = relative_path.parts[0] + conditional_dirs.add(top_level_dir) + + # Build versioned content for directories that contain conditional files + for conditional_dir in conditional_dirs: + self._build_conditional_docset( + conditional_dir, f"{conditional_dir}/python", "python" + ) + self._build_conditional_docset( + conditional_dir, f"{conditional_dir}/javascript", "js" + ) - logger.info("Building LangChain Labs content...") - self._build_unversioned_content("labs", "labs") + # Build unversioned content for directories that don't contain conditional files + for top_level_dir in top_level_dirs - conditional_dirs: + self._build_docset(top_level_dir, top_level_dir) - # Copy shared files (docs.json, images, etc.) + # Copy shared files (images, etc.) logger.info("Copying shared files...") self._copy_shared_files() - logger.info("✅ New structure build complete") + # Build config files + logger.info("Building config file...") + config_file_path = self.src_dir / "docs.json" + if config_file_path.exists(): + output_config_path = self.build_dir / "docs.json" + self._build_config_file( + config_file_path, output_config_path, conditional_dirs + ) - def _convert_yaml_to_json(self, yaml_file_path: Path, output_path: Path) -> None: - """Convert a YAML file to JSON format. + logger.info("✅ New structure build complete") - This method loads a docs.yml file using YAML safe_load and writes - the corresponding docs.json file to the build directory. + def _read_yaml_file(self, yaml_file_path: Path) -> dict: + """Read a YAML file and return its content. Args: yaml_file_path: Path to the source YAML file. - output_path: Path where the JSON file should be written. + + Returns: + The content of the YAML file as a dictionary. """ try: # Load YAML content with yaml_file_path.open("r", encoding="utf-8") as yaml_file: - yaml_content = yaml.safe_load(yaml_file) - - # Convert output path from .yml to .json - json_output_path = output_path.with_suffix(".json") - - # Write JSON content - with json_output_path.open("w", encoding="utf-8") as json_file: - json.dump(yaml_content, json_file, indent=2, ensure_ascii=False) + return yaml.safe_load(yaml_file) except yaml.YAMLError: logger.exception("Failed to parse YAML file %s", yaml_file_path) raise - except Exception: - logger.exception("Failed to convert %s to JSON", yaml_file_path) + + def _read_json_file(self, json_file_path: Path) -> dict: + """Read a JSON file and return its content. + + Args: + json_file_path: Path to the source JSON file. + + Returns: + The content of the JSON file as a dictionary. + """ + try: + with json_file_path.open("r", encoding="utf-8") as json_file: + return json.load(json_file) + except json.JSONDecodeError: + logger.exception("Failed to parse JSON file %s", json_file_path) raise def _rewrite_oss_links(self, content: str, target_language: str | None) -> str: @@ -139,7 +175,8 @@ def _rewrite_oss_links(self, content: str, target_language: str | None) -> str: Args: content: The markdown content to process. - target_language: Target language ("python" or "js") or None to skip rewriting. + target_language: Target language ("python" or "js") or None to skip + rewriting. Returns: Content with rewritten links. @@ -190,9 +227,7 @@ def _process_markdown_content( ) # Then rewrite /oss/ links to include language - content = self._rewrite_oss_links(content, target_language) - - return content + return self._rewrite_oss_links(content, target_language) except Exception: logger.exception("Failed to process markdown content from %s", file_path) raise @@ -259,15 +294,8 @@ def build_file(self, file_path: Path) -> None: # 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) - logger.info("Converted YAML to JSON: %s", relative_path) - # For other files, copy directly if supported - elif file_path.suffix.lower() in self.copy_extensions: + # Copy other supported files directly + 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) @@ -301,13 +329,6 @@ def _build_file_with_progress(self, file_path: Path, pbar: tqdm) -> bool: # 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 directly if file_path.suffix.lower() in self.copy_extensions: # Handle markdown files with preprocessing @@ -364,22 +385,25 @@ def build_files(self, file_paths: list[Path]) -> None: skipped_count, ) - def _build_langgraph_version(self, output_dir: str, target_language: str) -> None: - """Build LangGraph (oss/) content for a specific version. + def _build_conditional_docset( + self, source_dir: str, output_dir: str, target_language: str + ) -> None: + """Build a docset from a fenced directory. Args: - output_dir: Output directory (e.g., "langgraph/python", "langgraph/javascript"). + source_dir: Source directory (e.g., "oss", "labs"). + output_dir: Output directory (e.g., "oss/python", "oss/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") + src_path = self.src_dir / source_dir + if not src_path.exists(): + logger.warning("%s directory not found, skipping build", src_path) return all_files = [ file_path - for file_path in oss_dir.rglob("*") + for file_path in src_path.rglob("*") if file_path.is_file() and not self._is_shared_file(file_path) ] @@ -400,7 +424,7 @@ def _build_langgraph_version(self, output_dir: str, target_language: str) -> Non ) as pbar: for file_path in all_files: # Calculate relative path from oss/ directory - relative_path = file_path.relative_to(oss_dir) + relative_path = file_path.relative_to(src_path) # Build to output_dir/ (not output_dir/oss/) output_path = self.build_dir / output_dir / relative_path @@ -424,7 +448,7 @@ def _build_langgraph_version(self, output_dir: str, target_language: str) -> Non skipped_count, ) - def _build_unversioned_content(self, source_dir: str, output_dir: str) -> None: + def _build_docset(self, source_dir: str, output_dir: str) -> None: """Build unversioned content (langgraph-platform/ or labs/). Args: @@ -509,13 +533,6 @@ def _build_single_file( # 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 @@ -526,47 +543,159 @@ def _build_single_file( 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. + def _build_config_file( + self, file_path: Path, output_path: Path, conditional_dirs: set[str] + ) -> None: + """Build a docs.json file. 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. + output_path: Full output path for the file. + conditional_dirs: Set of conditional directories. """ - 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 + config = cast("MintlifyConfig", self._read_yaml_file(file_path)) + elif file_path.name == "docs.json" and file_path.suffix.lower() in { + ".json", + }: + config = cast("MintlifyConfig", self._read_json_file(file_path)) + else: + logger.warning("Unsupported config file: %s", file_path) + return + + def crawl_versions( + versions: list[NavigationVersion], + ) -> list[NavigationVersion]: + dropdown_mapping = [ + { + "title": "Python", + "icon": "python", + "version_path": "python", + }, + { + "title": "JavaScript", + "icon": "square-js", + "version_path": "javascript", + }, + ] + for index, version in enumerate(versions): + if self._config_version_has_conditional_pages( + version, conditional_dirs + ): + tabs = version.get("tabs") + if tabs: + versions[index] = NavigationVersion( + version=version["version"], + dropdowns=self._expand_config_tabs(tabs, dropdown_mapping), + ) + return versions + + def crawl_config(config: MintlifyConfig) -> MintlifyConfig: + navigation = config.get("navigation") + if navigation and navigation.get("versions"): + versions = navigation.get("versions") + if versions is not None: + navigation["versions"] = crawl_versions(versions) + return config + + output_config = crawl_config(copy.deepcopy(config)) + + # Write the processed docs content + with output_path.open("w", encoding="utf-8") as f: + json.dump(output_config, f, indent=2) + + def _config_version_has_conditional_pages( + self, version: NavigationVersion, conditional_dirs: set[str] + ) -> bool: + """Check if a docs version has conditional pages. + + Args: + version: The version dictionary to check. + conditional_dirs: Set of conditional directories. + """ + + def crawl_group(group: NavigationGroup) -> bool: + for page in group["pages"]: + if isinstance(page, str) and "/" in page: + first_dir = page.split("/", 1)[0] + if first_dir in conditional_dirs: + return True + elif isinstance(page, dict) and "group" in page: + if crawl_group(page): + return True + return False + + def crawl_tabs(tabs: list[NavigationTab]) -> bool: + for tab in tabs: + groups = tab.get("groups") + if groups: + for group in groups: + if crawl_group(group): + return True + return False + + tabs = version.get("tabs") + if tabs: + return crawl_tabs(tabs) + return False + def _expand_config_tabs( + self, tabs: list[NavigationTab], dropdown_mapping: list[dict] + ) -> list[NavigationDropdown]: + """Expand mintlify navigation tabs into dropdowns. + + Args: + tabs: The tabs to expand. + dropdown_mapping: A mapping of version names to their expanded versions. + """ + + def replace_page_version(page: str, version_path: str) -> str: + if "/" in page: + first_dir = page.split("/", 1)[0] + rest_of_path = "/".join(page.split("/")[1:]) + return f"{first_dir}/{version_path}/{rest_of_path}" + return f"{version_path}/{page}" + + def crawl_tabs( + tabs: list[NavigationTab], *, version_path: str + ) -> list[NavigationTab]: + for index, tab in enumerate(tabs): + tabs[index] = crawl_tab(tab, version_path=version_path) + return tabs + + def crawl_tab(tab: NavigationTab, *, version_path: str) -> NavigationTab: + groups = tab.get("groups") + if groups: + for index, group in enumerate(groups): + groups[index] = crawl_group(group, version_path=version_path) + return tab + + def crawl_group( + group: NavigationGroup, *, version_path: str + ) -> NavigationGroup: + for index, page in enumerate(group["pages"]): + if isinstance(page, str) and "/" in page: + group["pages"][index] = replace_page_version(page, version_path) + elif isinstance(page, dict) and "group" in page: + group["pages"][index] = crawl_group(page, version_path=version_path) + return group + + return [ + NavigationDropdown( + dropdown=mapping["title"], + icon=mapping["icon"], + tabs=crawl_tabs( + copy.deepcopy(tabs), version_path=mapping["version_path"] + ), + ) + for mapping in dropdown_mapping + ] + def _is_shared_file(self, file_path: Path) -> bool: """Check if a file should be shared between versions rather than duplicated. @@ -579,10 +708,6 @@ def _is_shared_file(self, file_path: Path) -> bool: # 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 @@ -592,10 +717,7 @@ def _is_shared_file(self, file_path: Path) -> bool: 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 + return file_path.suffix.lower() in {".js", ".css"} def _copy_shared_files(self) -> None: """Copy files that should be shared between versions.""" @@ -623,3 +745,35 @@ def _copy_shared_files(self) -> None: copied_count += 1 logger.info("✅ Shared files copied: %d files", copied_count) + + def _is_conditional_file(self, file_path: Path) -> bool: + """Check if a file is a code fenced file. + + Args: + file_path: Path to check. + + Returns: + True if the file is a code fenced file, False otherwise. + """ + if file_path.suffix.lower() not in {".md", ".mdx"}: + return False + + try: + with file_path.open("r", encoding="utf-8") as f: + content = f.read() + return has_conditional_blocks(content) + except Exception: + logger.exception("Failed to read file %s", file_path) + return False + + def _get_conditional_files(self) -> list[Path]: + """Get all fenced files in the source directory. + + Returns: + List of Path objects pointing to fenced files. + """ + return [ + file_path + for file_path in self.src_dir.rglob("*") + if file_path.is_file() and self._is_conditional_file(file_path) + ] diff --git a/pipeline/preprocessors/__init__.py b/pipeline/preprocessors/__init__.py index 7bf153da..c09584d5 100644 --- a/pipeline/preprocessors/__init__.py +++ b/pipeline/preprocessors/__init__.py @@ -1,5 +1,5 @@ """Markdown preprocessors for documentation pipeline.""" -from .markdown_preprocessor import preprocess_markdown +from .markdown_preprocessor import has_conditional_blocks, preprocess_markdown -__all__ = ["preprocess_markdown"] +__all__ = ["has_conditional_blocks", "preprocess_markdown"] diff --git a/pipeline/preprocessors/markdown_preprocessor.py b/pipeline/preprocessors/markdown_preprocessor.py index fac1cdc0..dea4f15b 100644 --- a/pipeline/preprocessors/markdown_preprocessor.py +++ b/pipeline/preprocessors/markdown_preprocessor.py @@ -14,6 +14,12 @@ logger = logging.getLogger(__name__) +CONDITIONAL_BLOCK_PATTERN = re.compile( + r"(?P[ \t]*):::(?P\w+)\s*\n" + r"(?P((?:.*\n)*?))" # Capture the content inside the block + r"(?P=indent)[ \t]*:::" # Match closing with same indentation +) + def _apply_conditional_rendering(md_text: str, target_language: str) -> str: """Apply conditional rendering to markdown content. @@ -37,12 +43,6 @@ def _apply_conditional_rendering(md_text: str, target_language: str) -> str: msg = "target_language must be 'python' or 'js'" raise ValueError(msg) - pattern = re.compile( - r"(?P[ \t]*):::(?P\w+)\s*\n" - r"(?P((?:.*\n)*?))" # Capture the content inside the block - r"(?P=indent)[ \t]*:::" # Match closing with same indentation - ) - def replace_conditional_blocks(match: re.Match) -> str: """Keep active conditionals.""" language = match.group("language") @@ -58,7 +58,12 @@ def replace_conditional_blocks(match: re.Match) -> str: # If the language does not match, return an empty string return "" - return pattern.sub(replace_conditional_blocks, md_text) + return CONDITIONAL_BLOCK_PATTERN.sub(replace_conditional_blocks, md_text) + + +def has_conditional_blocks(md_text: str) -> bool: + """Check if the markdown content has conditional blocks.""" + return CONDITIONAL_BLOCK_PATTERN.search(md_text) is not None def preprocess_markdown( diff --git a/pipeline/tools/mintlify.py b/pipeline/tools/mintlify.py new file mode 100644 index 00000000..4093f72c --- /dev/null +++ b/pipeline/tools/mintlify.py @@ -0,0 +1,47 @@ +"""TypedDict definitions for Mintlify docs.json configuration structure.""" + +from __future__ import annotations + +from typing import TypedDict + + +class MintlifyConfig(TypedDict): + """Mintlify config.""" + + navigation: Navigation + + +class Navigation(TypedDict, total=False): + """Navigation configuration.""" + + versions: list[NavigationVersion] | None + + +class NavigationVersion(TypedDict, total=False): + """Version within a navigation.""" + + version: str + dropdowns: list[NavigationDropdown] | None + tabs: list[NavigationTab] | None + + +class NavigationDropdown(TypedDict, total=False): + """Dropdown within a version.""" + + dropdown: str + icon: str + tabs: list[NavigationTab] | None + + +class NavigationTab(TypedDict, total=False): + """Tab within a version.""" + + tab: str + groups: list[NavigationGroup] | None + + +class NavigationGroup(TypedDict): + """Group within a tab.""" + + group: str + pages: list[str | NavigationGroup] diff --git a/src/docs.json b/src/docs.json index b73c950a..83c5db19 100644 --- a/src/docs.json +++ b/src/docs.json @@ -1,17 +1,17 @@ { "$schema": "https://mintlify.com/docs.json", - "theme": "maple", + "theme": "aspen", "name": "Docs by LangChain", "description": "Documentation for LangChain, LangGraph, LangGraph Platform, LangSmith, and more.", "colors": { - "primary": "#beb4fd", - "light": "#beb4fd", - "dark": "#1d3d3c" + "primary": "#2F6868", + "light": "#84C4C0", + "dark": "#84C4C0" }, "logo": { "light": "/images/brand/langchain-docs-teal.svg", "dark": "/images/brand/langchain-docs-lilac.svg", - "href": "https://docs.langchain.com/langgraph-platform" + "href": "https://docs.langchain.com/oss/python" }, "favicon": { "light": "/images/brand/favicon.svg", @@ -19,7 +19,7 @@ }, "fonts": { "heading": { - "family": "Manrope" + "family": "Inter" } }, "styling": { @@ -91,12 +91,6 @@ "youtube": "https://www.youtube.com/@LangChain" } }, - "scripts": [ - "/hide-version-picker.js" - ], - "styles": [ - "/hide-version-picker.css" - ], "banner": { "content": "Our new LangChain Academy Course Deep Research with LangGraph is now live! [Enroll for free](https://academy.langchain.com/courses/deep-research-with-langgraph/?utm_medium=internal&utm_source=docs&utm_campaign=q3-2025_deep-research-course_co)." }, @@ -112,210 +106,83 @@ }, "versions": [ { - "version": "Python", - "dropdowns": [ + "version": "LangGraph", + "tabs": [ { - "dropdown": "LangGraph", - "icon": "/images/brand/langgraph-pill.svg", - "description": "Framework for building reliable agents and workflows", - "tabs": [ + "tab": "Get started", + "groups": [ { - "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": "Get started", + "pages": [ + "oss/overview", + "oss/quickstart", + "oss/run-an-agent", + "oss/prebuilt-vs-low-level" ] }, { - "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": "Common architectures", + "pages": [ + "oss/agentic-architectures", + "oss/agentic-rag", + "oss/agent-supervisor", + "oss/sql-agent" ] }, { - "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": "Additional resources", + "pages": [ + "oss/case-studies", + "oss/template-applications" + ] + } + ] + }, + { + "tab": "Build agents", + "groups": [ + { + "group": "Basic configuration", + "pages": [ + "oss/prebuilts" + ] + }, + { + "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": "Reference", - "groups": [ + "group": "Components", + "pages": [ + "oss/models", { - "group": "LangGraph reference", + "group": "Tools", "pages": [ - "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" + "oss/tools", + "oss/call-tools" ] }, { - "group": "Prebuilt reference", + "group": "MCP", "pages": [ - "oss/python/reference/agents", - "oss/python/reference/supervisor", - "oss/python/reference/swarm", - "oss/python/reference/mcp" + "oss/mcp", + "oss/use-mcp" ] }, { - "group": "Error troubleshooting", + "group": "Multi-agent", "pages": [ - "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" + "oss/multi-agent", + "oss/multi-agent-prebuilts", + "oss/multi-agent-custom" ] } ] @@ -323,266 +190,121 @@ ] }, { - "dropdown": "LangGraph Platform", - "icon": "/images/brand/langgraph-platform-pill.svg", - "description": "Platform for building and deploying AI agents", - "tabs": [ + "tab": "Agent runtime", + "groups": [ { - "tab": "Get started", - "groups": [ + "group": "Capabilities", + "pages": [ + "oss/persistence", + "oss/durable-execution", { - "group": "Overview", + "group": "Streaming", "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" + "oss/streaming", + "oss/use-streaming" ] }, { - "group": "Quickstarts", + "group": "Human-in-the-loop", "pages": [ - "langgraph-platform/local-server", - "langgraph-platform/deployment-quickstart", - "langgraph-platform/quick-start-studio" + "oss/human-in-the-loop", + "oss/add-human-in-the-loop" ] }, { - "group": "Plans and deployment", - "pages": [ - "langgraph-platform/plans" - ] - } - ] - }, - { - "tab": "Build", - "groups": [ - { - "group": "Build an app with the LangGraph basics", + "group": "Time travel", "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" + "oss/time-travel", + "oss/use-time-travel" ] }, { - "group": "Data models", + "group": "Memory and context", "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" - ] - } + "oss/memory", + "oss/context", + "oss/add-memory" ] }, { - "group": "Core capabilities", + "group": "Subgraphs", "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" + "oss/subgraphs", + "oss/use-subgraphs" ] } ] }, { - "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": "Run and debug", + "pages": [ + "oss/local-server", + "oss/ui", + "oss/trace-agent", + "oss/evals" ] }, { - "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": "LangGraph APIs", + "pages": [ { - "group": "Server customization", + "group": "Graph API", "pages": [ - "langgraph-platform/custom-lifespan", - "langgraph-platform/custom-middleware", - "langgraph-platform/custom-routes" + "oss/graph-api", + "oss/use-graph-api" ] }, { - "group": "Data management", + "group": "Functional API", "pages": [ - "langgraph-platform/data-storage-and-privacy", - "langgraph-platform/semantic-search", - "langgraph-platform/configure-ttl" + "oss/functional-api", + "oss/use-functional-api" ] }, - { - "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" + "oss/pregel" ] } ] }, { - "dropdown": "LangChain Labs", - "icon": "/images/brand/langchain-labs-pill.svg", - "description": "Experimental AI products from LangChain", - "tabs": [ + "tab": "Reference", + "groups": [ { - "tab": "Overview", + "group": "LangGraph reference", "pages": [ - "labs/index" + "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" ] }, { - "tab": "Open SWE", + "group": "Prebuilt reference", "pages": [ - { - "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" - ] - } + "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" ] } ] @@ -590,411 +312,172 @@ ] }, { - "version": "JavaScript", - "dropdowns": [ + "version": "LangGraph Platform", + "tabs": [ { - "dropdown": "LangGraph", - "icon": "/images/brand/langgraph-pill.svg", - "description": "Framework for building reliable agents and workflows", - "tabs": [ + "tab": "Get started", + "groups": [ { - "tab": "Get started", - "groups": [ - { - "group": "Get started", - "pages": [ - "oss/javascript/overview", - "oss/javascript/quickstart", - "oss/javascript/run-an-agent", - "oss/javascript/prebuilt-vs-low-level" - ] - }, + "group": "Overview", + "pages": [ + "langgraph-platform/index", { - "group": "Common architectures", + "group": "Components", "pages": [ - "oss/javascript/agentic-architectures", - "oss/javascript/agentic-rag", - "oss/javascript/agent-supervisor", - "oss/javascript/sql-agent" + "langgraph-platform/components", + "langgraph-platform/langgraph-server", + "langgraph-platform/data-plane", + "langgraph-platform/control-plane" ] }, - { - "group": "Additional resources", - "pages": [ - "oss/javascript/case-studies", - "oss/javascript/template-applications" - ] - } + "langgraph-platform/application-structure" ] }, { - "tab": "Build agents", - "groups": [ - { - "group": "Basic configuration", - "pages": [ - "oss/javascript/prebuilts" - ] - }, - { - "group": "Low-level configuration", - "pages": [ - "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": "Quickstarts", + "pages": [ + "langgraph-platform/local-server", + "langgraph-platform/deployment-quickstart", + "langgraph-platform/quick-start-studio" ] }, { - "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": "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": "Data models", + "pages": [ { - "group": "Run and debug", + "group": "Assistants", "pages": [ - "oss/javascript/local-server", - "oss/javascript/ui", - "oss/javascript/trace-agent", - "oss/javascript/evals" + "langgraph-platform/assistants", + "langgraph-platform/configuration-cloud", + "langgraph-platform/use-threads" ] }, { - "group": "LangGraph APIs", + "group": "Runs", "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" + "langgraph-platform/background-run", + "langgraph-platform/same-thread", + "langgraph-platform/cron-jobs", + "langgraph-platform/stateless-runs", + "langgraph-platform/configurable-headers" ] } ] }, { - "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": "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": "Error troubleshooting", + "group": "Double-texting", "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" + "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" + ] } ] }, { - "dropdown": "LangGraph Platform", - "icon": "/images/brand/langgraph-platform-pill.svg", - "description": "Platform for building and deploying AI agents", - "tabs": [ + "tab": "Deploy", + "groups": [ { - "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": "Overview", + "pages": [ + "langgraph-platform/deployment-options", + "langgraph-platform/cloud", + "langgraph-platform/hybrid", + "langgraph-platform/self-hosted" ] }, { - "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": "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": "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": "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": "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" - ] - } + "group": "Scalability & resilience", + "pages": [ + "langgraph-platform/scalability-and-resilience" ] }, { @@ -1014,88 +497,75 @@ ] }, { - "tab": "Reference", + "group": "Tutorials", "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" + "langgraph-platform/autogen-integration", + "langgraph-platform/use-stream-react", + "langgraph-platform/generative-ui-react" ] } ] }, { - "dropdown": "LangChain Labs", - "icon": "/images/brand/langchain-labs-pill.svg", - "description": "Experimental AI products from LangChain", - "tabs": [ + "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" + ] + } + ] + }, + { + "version": "LangChain Labs", + "tabs": [ + { + "tab": "Overview", + "pages": [ + "labs/index" + ] + }, + { + "tab": "Open SWE", + "pages": [ { - "tab": "Overview", + "group": "Get Started", "pages": [ - "labs/index" + "labs/swe/index" ] }, { - "tab": "Deep Agents", + "group": "Usage", "pages": [ - { - "group": "Get started", - "pages": [ - "labs/deep-agents/overview", - "labs/deep-agents/quickstart" - ] - }, - { - "group": "Configuration", - "pages": [ - "labs/deep-agents/configuration-options", - "labs/deep-agents/built-in-components" - ] - } + "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" ] }, { - "tab": "Open SWE", + "group": "Development Setup", "pages": [ - { - "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" - ] - } + "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" ] } ] diff --git a/src/hide-version-picker.css b/src/hide-version-picker.css deleted file mode 100644 index df1036f8..00000000 --- a/src/hide-version-picker.css +++ /dev/null @@ -1,27 +0,0 @@ -/** - * 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 deleted file mode 100644 index 57384d7b..00000000 --- a/src/hide-version-picker.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * 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/src/images/brand/single-icons/langchain-labs.svg b/src/images/brand/single-icons/langchain-labs.svg new file mode 100644 index 00000000..1909321c --- /dev/null +++ b/src/images/brand/single-icons/langchain-labs.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/brand/single-icons/langchain.svg b/src/images/brand/single-icons/langchain.svg new file mode 100644 index 00000000..2e06698e --- /dev/null +++ b/src/images/brand/single-icons/langchain.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/brand/single-icons/langgraph-platform.svg b/src/images/brand/single-icons/langgraph-platform.svg new file mode 100644 index 00000000..e3a59605 --- /dev/null +++ b/src/images/brand/single-icons/langgraph-platform.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/images/brand/single-icons/langgraph.svg b/src/images/brand/single-icons/langgraph.svg new file mode 100644 index 00000000..33fbe98b --- /dev/null +++ b/src/images/brand/single-icons/langgraph.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/images/brand/single-icons/langsmith.svg b/src/images/brand/single-icons/langsmith.svg new file mode 100644 index 00000000..ddad966f --- /dev/null +++ b/src/images/brand/single-icons/langsmith.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/index.mdx b/src/index.mdx index 12e3f33d..1e07ca7b 100644 --- a/src/index.mdx +++ b/src/index.mdx @@ -8,7 +8,7 @@ mode: "wide" # Frameworks - + Low-level orchestration framework for building, managing, and deploying long-running, stateful agents. diff --git a/src/style.css b/src/style.css index 59a90abe..8dc7383a 100644 --- a/src/style.css +++ b/src/style.css @@ -1,74 +1,46 @@ -/* Minimalistic Navigation Tab Styling - Using Lavender Theme */ - -/* Target the main navbar container */ -#navbar-transition-maple { - background: rgba(229, 231, 235, 0.5) !important; /* gray-200/50 to match site palette */ - border-bottom: 1px solid rgba(229, 231, 235, 0.7) !important; /* gray-200/70 to match existing border */ -} - -/* Target the navigation tabs container */ -.nav-tabs { - background: transparent !important; - padding: 4px 12px !important; - border-radius: 8px !important; -} - -/* Target individual tab items - clean and minimal */ -a.nav-tabs-item { - position: relative !important; - font-weight: 500 !important; - font-size: 14px !important; - border-radius: 6px !important; - margin: 0 2px !important; - padding: 8px 12px !important; - transition: all 0.2s ease !important; - background: transparent !important; - border: none !important; - text-decoration: none !important; - color: #64748b !important; -} - -/* Remove the default bottom border from Mintlify */ -a.nav-tabs-item .absolute.bottom-0 { - display: none !important; -} - -/* Override any inline styles that might be applied by JavaScript - but not for active tabs */ -a.nav-tabs-item[style]:not([aria-selected="true"]):not(.active):not([aria-current="page"]):not(.font-semibold):not([class*="font-semibold"]) { - background: transparent !important; - border: none !important; -} - -/* Tab hover states - match site's hover grey */ -a.nav-tabs-item:hover:not(.font-semibold):not([class*="font-semibold"]) { - background: rgba(229, 231, 235, 0.8) !important; /* gray-200/80 to match site hover */ - color: #1f2937 !important; /* gray-800 to match site text */ -} - -/* Active/selected tab states - connected to content area */ -a.nav-tabs-item[aria-selected="true"], -a.nav-tabs-item.active, -a.nav-tabs-item[aria-current="page"], -a.nav-tabs-item[data-active="true"], -a.nav-tabs-item.selected, -/* Target active tabs by their distinctive class pattern */ -a.nav-tabs-item.font-semibold, -a.nav-tabs-item[class*="font-semibold"] { - background: white !important; - color: #beb4fd !important; - font-weight: 600 !important; - border-bottom: 1px solid white !important; - margin-bottom: -1px !important; - position: relative !important; - z-index: 1 !important; -} - -/* Active tab indicator - removed, using only container highlight */ - -/* Focus states for accessibility */ -a.nav-tabs-item:focus-visible { - outline: 2px solid #beb4fd !important; - outline-offset: 2px !important; +/* Light mode CSS variables */ +:root { + /* Light Mode Colors - Figma Design Tokens */ + --bg-primary: #ffffff; + --bg-tertiary: #f4f4f5; + --text-primary-900: #101828; + --text-secondary-700: #3f3f46; + --text-tertiary-600: #51525c; + --text-quaternary-500: #70707b; + --border-primary: #d1d1d6; + --border-secondary: #e4e4e7; + --border-tertiary: #f4f4f5; + --brand-600: #2f6868; + --brand-100: #d9eeec; + --fg-primary-900: #1a1a1e; + + /* Typography - Figma Tokens */ + --font-family: "Inter", system-ui, -apple-system, sans-serif; +} + +/* Dark Mode Colors */ +@media (prefers-color-scheme: dark) { + :root { + --bg-primary: #1a1a1e; + --bg-tertiary: #2a2a2e; + --text-primary-900: #ffffff; + --text-secondary-700: #d1d1d6; + --text-tertiary-600: #a1a1aa; + --text-quaternary-500: #8a8a95; + --border-primary: #3f3f46; + --border-secondary: #2a2a2e; + --border-tertiary: #1f1f23; + --brand-600: #2f6868; + --brand-100: #1a2c2a; + --fg-primary-900: #ffffff; + } +} + +/* Base styles */ +body { + background-color: var(--bg-primary); + color: var(--text-secondary-700); + font-family: var(--font-family); } /* Wider content area for better code display (100-120 character lines) */ @@ -102,39 +74,118 @@ code, padding-right: 2rem !important; } -/* Dark mode support */ -.dark #navbar-transition-maple { - background: rgba(55, 65, 81, 0.5) !important; /* gray-700/50 to match site dark palette */ - border-bottom: 1px solid rgba(255, 255, 255, 0.07) !important; /* white/7% to match existing dark border */ + +/* Style "breadcrumbs" link element */ +.inline-flex.items-center.gap-1\.5.text-sm.text-gray-500 { + color: var(--colours-text-text-quaternary-500, #70707B) !important; + font-family: Inter !important; + font-size: 12px !important; + font-style: normal !important; + font-weight: 500 !important; + line-height: 100% !important; + letter-spacing: 0.48px !important; + text-transform: uppercase !important; +} + +#page-title { + font-family: var(--font-family); + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: 120%; + letter-spacing: -0.72px; +} + +#mdx-content { + color: var(--text-secondary-700); + font-family: var(--font-family); + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 150%; +} + +/* Reset browser default heading styles */ +h1, h2, h3, h4, h5, h6 { + font-weight: normal; + margin: 0; +} + +/* Heading hierarchy styles */ +h1, #mdx-content h1, .prose h1, article h1, main h1 { + font-family: var(--font-family); + font-size: 24px; + font-style: normal; + font-weight: 400 !important; + line-height: 120%; /* 28.8px */ + letter-spacing: -0.72px; +} + +h2, #mdx-content h2 { + color: var(--text-primary-900); + font-family: var(--font-family); + font-size: 18px; + font-style: normal; + font-weight: 400 !important; + line-height: 120%; + letter-spacing: -0.72px; +} + +h3, #mdx-content h3 { + color: var(--text-primary-900); + font-family: var(--font-family); + font-size: 16px; + font-weight: 400 !important; + line-height: 130%; + letter-spacing: -0.36px; + margin-top: 1.25rem; + margin-bottom: 0.5rem; +} + +h4, #mdx-content h4 { + color: var(--text-primary-900); + font-family: var(--font-family); + font-size: 14px; + font-weight: 400 !important; + line-height: 135%; + letter-spacing: -0.32px; + margin-top: 1rem; + margin-bottom: 0.5rem; +} + +h5, #mdx-content h5 { + color: var(--text-quaternary-500); + font-family: var(--font-family); + font-size: 12px; + font-style: normal; + font-weight: 500 !important; + line-height: 100%; + letter-spacing: 0.48px; + text-transform: uppercase; } -.dark .nav-tabs { - background: transparent !important; +/* Nav dropdown styling */ +.nav-dropdown-item-icon, +.nav-dropdown-item-icon > img { + background-color: transparent !important; + border: none !important; } -.dark a.nav-tabs-item { - background: transparent !important; - color: #9ca3af !important; +/* Hide nav dropdown descriptions by default */ +.nav-dropdown-item-description { + display: none !important; } -.dark a.nav-tabs-item[style]:not([aria-selected="true"]):not(.active):not([aria-current="page"]):not(.font-semibold):not([class*="font-semibold"]) { - background: transparent !important; +/* Show nav dropdown descriptions when dropdown is open */ +[data-state="open"] .nav-dropdown-item-description { + display: block !important; } -.dark a.nav-tabs-item:hover:not(.font-semibold):not([class*="font-semibold"]) { - background: rgba(55, 65, 81, 0.8) !important; /* gray-700/80 to match site dark hover */ - color: #f9fafb !important; /* gray-50 for better contrast */ +.topbar-right-container { + flex: 0; } -.dark a.nav-tabs-item[aria-selected="true"], -.dark a.nav-tabs-item.active, -.dark a.nav-tabs-item[aria-current="page"], -.dark a.nav-tabs-item.font-semibold, -.dark a.nav-tabs-item[class*="font-semibold"] { - background: #1f2937 !important; - color: #beb4fd !important; - border-bottom: 1px solid #1f2937 !important; - margin-bottom: -1px !important; - position: relative !important; - z-index: 1 !important; +/* Targets the container that has the search input */ +:has(> .topbar-right-container) > :nth-child(2) { + justify-content: end; } \ No newline at end of file