diff --git a/pipeline/core/builder.py b/pipeline/core/builder.py index f7488e399..08becb850 100644 --- a/pipeline/core/builder.py +++ b/pipeline/core/builder.py @@ -51,6 +51,7 @@ def __init__(self, src_dir: Path, build_dir: Path) -> None: ".yaml", ".css", ".js", + ".html", } # Mapping of language codes to full names for URLs @@ -156,8 +157,8 @@ def rewrite_link(match: re.Match) -> str: url = match.group(2) # The URL post = match.group(3) # Everything after the URL - # Only rewrite absolute /oss/ paths that don't contain 'images' - if url.startswith("/oss/") and "images" not in url: + # Only rewrite absolute /oss/ paths that don't contain 'images' or 'plugins' + if url.startswith("/oss/") and "images" not in url and "plugins" not in url: parts = url.split("/") # Insert full language name after "oss" parts.insert(2, self.language_url_names[target_language]) @@ -743,8 +744,11 @@ def is_shared_file(self, file_path: Path) -> bool: if "snippets" in relative_path.parts: return True + if "plugins" in relative_path.parts: + return True + # JavaScript and CSS files should be shared (used for custom scripts/styles) - return file_path.suffix.lower() in {".js", ".css"} + return file_path.suffix.lower() in {".js", ".css", ".html", ".json"} def _copy_shared_files(self) -> None: """Copy files that should be shared between versions.""" diff --git a/pyproject.toml b/pyproject.toml index 4231dbe5f..b9abdd8cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,7 +70,8 @@ asyncio_default_fixture_loop_scope = "function" line-length = 88 extend-exclude = [ "scripts/update_mdx.py", - "pipeline/tools/notebook/convert.py" + "pipeline/tools/notebook/convert.py", + "src/plugins/middleware_visualization/generate_middleware_diagrams.py" ] @@ -133,3 +134,9 @@ ignore = [ [tool.ruff.lint.pydocstyle] convention = "google" + + +[tool.mypy] +exclude = [ + "src/plugins/middleware_visualization/generate_middleware_diagrams.py", +] diff --git a/src/oss/images/0000.svg b/src/oss/images/0000.svg deleted file mode 100644 index c6ac7fdfc..000000000 --- a/src/oss/images/0000.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agent__end__ diff --git a/src/oss/images/0001.svg b/src/oss/images/0001.svg deleted file mode 100644 index 79d79403f..000000000 --- a/src/oss/images/0001.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agenttools__end__ diff --git a/src/oss/images/0010.svg b/src/oss/images/0010.svg deleted file mode 100644 index b6ecf5516..000000000 --- a/src/oss/images/0010.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agentpre_model_hook__end__ diff --git a/src/oss/images/0011.svg b/src/oss/images/0011.svg deleted file mode 100644 index 1f218281b..000000000 --- a/src/oss/images/0011.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agenttoolspre_model_hook__end__ diff --git a/src/oss/images/0100.svg b/src/oss/images/0100.svg deleted file mode 100644 index 8fa789f7a..000000000 --- a/src/oss/images/0100.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agentpost_model_hook__end__ diff --git a/src/oss/images/0101.svg b/src/oss/images/0101.svg deleted file mode 100644 index e746496fd..000000000 --- a/src/oss/images/0101.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agenttoolspost_model_hook__end__ diff --git a/src/oss/images/0110.svg b/src/oss/images/0110.svg deleted file mode 100644 index 34f2ee59e..000000000 --- a/src/oss/images/0110.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agentpre_model_hookpost_model_hook__end__ diff --git a/src/oss/images/0111.svg b/src/oss/images/0111.svg deleted file mode 100644 index 4a8f5c77e..000000000 --- a/src/oss/images/0111.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agenttoolspre_model_hookpost_model_hook__end__ diff --git a/src/oss/images/1000.svg b/src/oss/images/1000.svg deleted file mode 100644 index 84d439aba..000000000 --- a/src/oss/images/1000.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agentgenerate_structured_response__end__ diff --git a/src/oss/images/1001.svg b/src/oss/images/1001.svg deleted file mode 100644 index 3066654d9..000000000 --- a/src/oss/images/1001.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agenttoolsgenerate_structured_response__end__ diff --git a/src/oss/images/1010.svg b/src/oss/images/1010.svg deleted file mode 100644 index 445f405c5..000000000 --- a/src/oss/images/1010.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agentpre_model_hookgenerate_structured_response__end__ diff --git a/src/oss/images/1011.svg b/src/oss/images/1011.svg deleted file mode 100644 index ed5ab0bb5..000000000 --- a/src/oss/images/1011.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agenttoolspre_model_hookgenerate_structured_response__end__ diff --git a/src/oss/images/1100.svg b/src/oss/images/1100.svg deleted file mode 100644 index 23e2d5b71..000000000 --- a/src/oss/images/1100.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agentpost_model_hookgenerate_structured_response__end__ diff --git a/src/oss/images/1101.svg b/src/oss/images/1101.svg deleted file mode 100644 index acc1d0403..000000000 --- a/src/oss/images/1101.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agenttoolspost_model_hookgenerate_structured_response__end__ diff --git a/src/oss/images/1110.svg b/src/oss/images/1110.svg deleted file mode 100644 index efe832965..000000000 --- a/src/oss/images/1110.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agentpre_model_hookpost_model_hookgenerate_structured_response__end__ diff --git a/src/oss/images/1111.svg b/src/oss/images/1111.svg deleted file mode 100644 index b903b4ed6..000000000 --- a/src/oss/images/1111.svg +++ /dev/null @@ -1 +0,0 @@ -__start__agenttoolspre_model_hookpost_model_hookgenerate_structured_response__end__ diff --git a/src/oss/langchain/middleware.mdx b/src/oss/langchain/middleware.mdx index 49a51fb3b..fe4bb7e87 100644 --- a/src/oss/langchain/middleware.mdx +++ b/src/oss/langchain/middleware.mdx @@ -877,21 +877,15 @@ Build custom middleware by implementing hooks that run at specific points in the #### Node-style hooks -Run at specific points in the execution flow: +Run at specific points in the execution flow. -:::python -- `before_agent` - Before agent starts (once per invocation) -- `before_model` - Before each model call -- `after_model` - After each model response -- `after_agent` - After agent completes (up to once per invocation) -::: +**Try it:** The interactive widget below shows all available hooks and lets you toggle different combinations to see how they affect the agent execution graph: -:::js -- `beforeAgent` - Before agent starts (once per invocation) -- `beforeModel` - Before each model call -- `afterModel` - After each model response -- `afterAgent` - After agent completes (up to once per invocation) -::: + **Example: Logging middleware** diff --git a/src/oss/langgraph/use-functional-api.mdx b/src/oss/langgraph/use-functional-api.mdx index cdb0ae819..a2d2b73bd 100644 --- a/src/oss/langgraph/use-functional-api.mdx +++ b/src/oss/langgraph/use-functional-api.mdx @@ -1475,10 +1475,10 @@ list(graph.get_state_history(config)) # [!code highlight] ```typescript const config = { configurable: { - thread_id: "1", # [!code highlight] + thread_id: "1", // [!code highlight] }, }; -const history = []; # [!code highlight] +const history = []; // [!code highlight] for await (const state of graph.getStateHistory(config)) { history.push(state); } diff --git a/src/plugins/middleware_visualization/README.md b/src/plugins/middleware_visualization/README.md new file mode 100644 index 000000000..d2a1c70a4 --- /dev/null +++ b/src/plugins/middleware_visualization/README.md @@ -0,0 +1,63 @@ +# Middleware Hooks Visualizer + +Minimal interactive visualizer for LangChain middleware hooks and agent graphs. + +## Features + +- **Language-specific diagrams**: Automatically switches between Python (snake_case) and JavaScript (camelCase) naming based on active tab +- **Interactive tooltips**: Hover over checkboxes to see what each hook does +- **Compact layout**: Optimized spacing for better visual hierarchy +- **Mintlify integration**: Uses Mintlify design tokens for consistent styling + +## Usage + +The `index.html` file can be embedded directly into Mintlify documentation: + +```html + +``` + +**Binary naming scheme (5 bits):** +``` +Bit 0: tools +Bit 1: before_agent +Bit 2: before_model +Bit 3: after_model +Bit 4: after_agent +``` + +Example: `10110` = tools + before_model + after_model + +## Files + +- `index.html` - Embeddable widget with interactive controls and diagram rendering +- `diagrams_python.js` - Python version with snake_case naming (e.g., `before_agent`) +- `diagrams_js.js` - JavaScript version with camelCase naming (e.g., `beforeAgent`) +- `generate_middleware_diagrams.py` - Diagram generator script + +## Regenerating Diagrams + +To regenerate the diagrams after making changes to middleware hooks: + +```bash +uv run python src/plugins/middleware_visualization/generate_middleware_diagrams.py +``` + +This generates three files: +- `diagrams_python.js` - Python diagrams with snake_case hooks +- `diagrams_js.js` - JavaScript diagrams with camelCase hooks + +### Diagram Configuration + +The generator creates compact diagrams with: +- `nodeSpacing: 30` - Horizontal spacing between nodes +- `rankSpacing: 40` - Vertical spacing between ranks +- `padding: 10` - Diagram padding + +Adjust these values in `generate_middleware_diagrams.py` line 144-150 to modify diagram height. + +**Note**: Mintlify's dev server doesn't serve JSON files, so we convert the data to JavaScript files that can be loaded via ` + + diff --git a/tests/unit_tests/test_builder.py b/tests/unit_tests/test_builder.py index 6ce5d874e..e7d485d2a 100644 --- a/tests/unit_tests/test_builder.py +++ b/tests/unit_tests/test_builder.py @@ -37,6 +37,7 @@ def test_builder_initialization() -> None: ".yaml", ".css", ".js", + ".html", }
__start__
agent
__end__
tools
pre_model_hook
post_model_hook
generate_structured_response