diff --git a/libs/cli/langgraph_cli/config.py b/libs/cli/langgraph_cli/config.py index 7c91c4e9e..5c512b58c 100644 --- a/libs/cli/langgraph_cli/config.py +++ b/libs/cli/langgraph_cli/config.py @@ -778,7 +778,22 @@ def _update_graph_paths( FileNotFoundError: If the local file (module) does not actually exist on disk. IsADirectoryError: If `module_str` points to a directory instead of a file. """ - for graph_id, import_str in config["graphs"].items(): + for graph_id, data in config["graphs"].items(): + if isinstance(data, dict): + # Then we're looking for a 'path' key + if "path" not in data: + raise ValueError( + f"Graph '{graph_id}' must contain a 'path' key if " + f" it is a dictionary." + ) + import_str = data["path"] + elif isinstance(data, str): + import_str = data + else: + raise ValueError( + f"Graph '{graph_id}' must be a string or a dictionary with a 'path' key." + ) + module_str, _, attr_str = import_str.partition(":") if not module_str or not attr_str: message = ( @@ -818,7 +833,10 @@ def _update_graph_paths( "Add its containing package to 'dependencies' list." ) # update the config - config["graphs"][graph_id] = f"{module_str}:{attr_str}" + if isinstance(data, dict): + config["graphs"][graph_id]["path"] = f"{module_str}:{attr_str}" + else: + config["graphs"][graph_id] = f"{module_str}:{attr_str}" def _update_auth_path( diff --git a/libs/cli/tests/unit_tests/cli/test_cli.py b/libs/cli/tests/unit_tests/cli/test_cli.py index ecce0af92..53954da5e 100644 --- a/libs/cli/tests/unit_tests/cli/test_cli.py +++ b/libs/cli/tests/unit_tests/cli/test_cli.py @@ -196,6 +196,50 @@ def test_dockerfile_command_basic() -> None: assert save_path.exists() +def test_dockerfile_command_new_style_config() -> None: + """Test `dockerfile` command with a new style config. + + This config format allows specifying agent data as a dictionary. + { + "graphs": { + "agent1": { + "path": ... # path to graph definition, + ... # other fields + } + } + } + """ + runner = CliRunner() + config_content = { + "dependencies": ["./my_agent"], + "graphs": { + "agent": { + "path": "./my_agent/agent.py:graph", + "description": "This is a test agent", + } + }, + "env": ".env", + } + with temporary_config_folder(config_content) as temp_dir: + save_path = temp_dir / "Dockerfile" + # Add agent.py file + agent_path = temp_dir / "my_agent" / "agent.py" + agent_path.parent.mkdir(parents=True, exist_ok=True) + agent_path.touch() + + result = runner.invoke( + cli, + ["dockerfile", str(save_path), "--config", str(temp_dir / "config.json")], + ) + + # Assert command was successful + assert result.exit_code == 0, result.output + assert "✅ Created: Dockerfile" in result.output + + # Check if Dockerfile was created + assert save_path.exists() + + def test_dockerfile_command_with_docker_compose() -> None: """Test the 'dockerfile' command with Docker Compose configuration.""" runner = CliRunner()