From 423397b6a1231e09478034ce8b20be1e5989f4a3 Mon Sep 17 00:00:00 2001 From: mikemikimike <13286568797@163.com> Date: Sat, 29 Aug 2026 14:56:39 +0800 Subject: [PATCH 1/2] fix(langchain): support Windows graph paths Signed-off-by: mikemikimike <13286568797@163.com> --- .../plugins/langchain/langgraph_workflow.py | 20 +++++++++++------- .../tests/test_langgraph_workflow.py | 21 +++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/nvidia_nat_langchain/src/nat/plugins/langchain/langgraph_workflow.py b/packages/nvidia_nat_langchain/src/nat/plugins/langchain/langgraph_workflow.py index 83bd043fed..5d177055af 100644 --- a/packages/nvidia_nat_langchain/src/nat/plugins/langchain/langgraph_workflow.py +++ b/packages/nvidia_nat_langchain/src/nat/plugins/langchain/langgraph_workflow.py @@ -193,6 +193,17 @@ def convert_to_chat_response_chunk(value: LanggraphWrapperOutput) -> ChatRespons return ChatResponseChunk.from_string(text) +def split_graph_path(graph: str) -> tuple[str, str]: + """Split a graph reference into its module path and graph name.""" + module_path, separator, name = graph.rpartition(":") + if not separator or not module_path or not name: + raise ValueError( + f"Graph definition path '{graph}' must contain a non-empty module path and graph name " + "separated by a colon (e.g., '/path/to/module.py:graph_name').") + + return module_path, name + + @register_function(config_type=LanggraphWrapperConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN]) async def register(config: LanggraphWrapperConfig, b: Builder): @@ -227,14 +238,7 @@ async def register(config: LanggraphWrapperConfig, b: Builder): f"Env '{config.env}' is not a valid type. At the moment, we only support strings and dictionaries.") # Now process the graph. - # Check that config.graph contains exactly one colon - if config.graph.count(":") != 1: - raise ValueError( - f"Graph definition path '{config.graph}' must contain exactly one colon to split module and name " - f"(e.g., '/path/to/module.py:graph_name'). Found {config.graph.count(':')}.") - - # Split the graph path into module and name - module_path, name = config.graph.rsplit(":", 1) + module_path, name = split_graph_path(config.graph) unique_module_name = f"langgraph_workflow_{uuid.uuid4().hex[:8]}" diff --git a/packages/nvidia_nat_langchain/tests/test_langgraph_workflow.py b/packages/nvidia_nat_langchain/tests/test_langgraph_workflow.py index 4e8b8642d9..758c5cb835 100644 --- a/packages/nvidia_nat_langchain/tests/test_langgraph_workflow.py +++ b/packages/nvidia_nat_langchain/tests/test_langgraph_workflow.py @@ -28,6 +28,27 @@ from nat.plugins.langchain.langgraph_workflow import LanggraphWrapperFunction from nat.plugins.langchain.langgraph_workflow import LanggraphWrapperInput from nat.plugins.langchain.langgraph_workflow import LanggraphWrapperOutput +from nat.plugins.langchain.langgraph_workflow import split_graph_path + + +@pytest.mark.parametrize( + ("graph", "expected"), + [ + ("/path/to/module.py:graph_name", ("/path/to/module.py", "graph_name")), + (r"C:\\path\\to\\module.py:graph", (r"C:\\path\\to\\module.py", "graph")), + ("relative.py:graph", ("relative.py", "graph")), + ], +) +def test_split_graph_path(graph, expected): + """Graph references split at the final colon, including Windows drive paths.""" + assert split_graph_path(graph) == expected + + +@pytest.mark.parametrize("graph", ["module.py", ":graph", "module.py:", ""]) +def test_split_graph_path_rejects_missing_parts(graph): + """Graph references require both a module path and graph name.""" + with pytest.raises(ValueError, match="non-empty module path"): + split_graph_path(graph) class TestConvertChatRequest: From dc6c80635e5a66b2dd85ea9c8c15852ac8806fdd Mon Sep 17 00:00:00 2001 From: mikemikimike <13286568797@163.com> Date: Sun, 30 Aug 2026 08:56:17 +0800 Subject: [PATCH 2/2] style(langchain): apply yapf formatting Signed-off-by: mikemikimike <13286568797@163.com> --- .../src/nat/plugins/langchain/langgraph_workflow.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/nvidia_nat_langchain/src/nat/plugins/langchain/langgraph_workflow.py b/packages/nvidia_nat_langchain/src/nat/plugins/langchain/langgraph_workflow.py index 5d177055af..657bccadb7 100644 --- a/packages/nvidia_nat_langchain/src/nat/plugins/langchain/langgraph_workflow.py +++ b/packages/nvidia_nat_langchain/src/nat/plugins/langchain/langgraph_workflow.py @@ -197,9 +197,8 @@ def split_graph_path(graph: str) -> tuple[str, str]: """Split a graph reference into its module path and graph name.""" module_path, separator, name = graph.rpartition(":") if not separator or not module_path or not name: - raise ValueError( - f"Graph definition path '{graph}' must contain a non-empty module path and graph name " - "separated by a colon (e.g., '/path/to/module.py:graph_name').") + raise ValueError(f"Graph definition path '{graph}' must contain a non-empty module path and graph name " + "separated by a colon (e.g., '/path/to/module.py:graph_name').") return module_path, name