diff --git a/python/sglang/srt/server_args_config_parser.py b/python/sglang/srt/server_args_config_parser.py index 24de2e967..17724ff7b 100644 --- a/python/sglang/srt/server_args_config_parser.py +++ b/python/sglang/srt/server_args_config_parser.py @@ -4,6 +4,7 @@ Handles merging of YAML configuration files with command-line arguments. """ import argparse +import json import logging from pathlib import Path from typing import Any, Dict, List @@ -151,6 +152,8 @@ class ConfigArgumentMerger: self._add_boolean_arg(args, key, value) elif isinstance(value, list): self._add_list_arg(args, key, value) + elif isinstance(value, dict): + self._add_scalar_arg(args, key, json.dumps(value)) else: self._add_scalar_arg(args, key, value) diff --git a/test/registered/unit/server_args/test_server_args.py b/test/registered/unit/server_args/test_server_args.py index b6e1175d1..348025739 100644 --- a/test/registered/unit/server_args/test_server_args.py +++ b/test/registered/unit/server_args/test_server_args.py @@ -14,6 +14,7 @@ from sglang.srt.model_executor.cuda_graph_config import ( PhaseConfig, ) from sglang.srt.server_args import PortArgs, ServerArgs, prepare_server_args +from sglang.srt.server_args_config_parser import ConfigArgumentMerger from sglang.test.ci.ci_register import register_cpu_ci from sglang.test.test_utils import ( DEFAULT_SMALL_MODEL_NAME_FOR_TEST_QWEN, @@ -44,6 +45,30 @@ class TestPrepareServerArgs(CustomTestCase): {"rope_scaling": {"factor": 2.0, "rope_type": "linear"}}, ) + def test_config_nested_dict_args_are_json(self): + with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: + f.write("mm-process-config:\n image:\n resize: 128\n") + config_file = f.name + + try: + parser = server_args_module.argparse.ArgumentParser() + ServerArgs.add_cli_args(parser) + merged = ConfigArgumentMerger(parser).merge_config_with_args( + [ + "--config", + config_file, + "--model-path", + DEFAULT_SMALL_MODEL_NAME_FOR_TEST_QWEN, + ] + ) + value = merged[merged.index("--mm-process-config") + 1] + parsed = parser.parse_args(merged) + + self.assertEqual(json.loads(value), {"image": {"resize": 128}}) + self.assertEqual(parsed.mm_process_config, {"image": {"resize": 128}}) + finally: + os.unlink(config_file) + class TestLoadBalanceMethod(unittest.TestCase): def test_non_pd_defaults_to_round_robin(self):