vllm-sr 0.1.0b2.dev20260115081807__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. vllm_sr-0.1.0b2.dev20260115081807/MANIFEST.in +18 -0
  2. vllm_sr-0.1.0b2.dev20260115081807/PKG-INFO +107 -0
  3. vllm_sr-0.1.0b2.dev20260115081807/README.md +77 -0
  4. vllm_sr-0.1.0b2.dev20260115081807/cli/__init__.py +3 -0
  5. vllm_sr-0.1.0b2.dev20260115081807/cli/commands/__init__.py +9 -0
  6. vllm_sr-0.1.0b2.dev20260115081807/cli/commands/config.py +91 -0
  7. vllm_sr-0.1.0b2.dev20260115081807/cli/commands/generate.py +73 -0
  8. vllm_sr-0.1.0b2.dev20260115081807/cli/commands/init.py +96 -0
  9. vllm_sr-0.1.0b2.dev20260115081807/cli/commands/serve.py +206 -0
  10. vllm_sr-0.1.0b2.dev20260115081807/cli/commands/show_config.py +146 -0
  11. vllm_sr-0.1.0b2.dev20260115081807/cli/commands/show_defaults.py +29 -0
  12. vllm_sr-0.1.0b2.dev20260115081807/cli/commands/validate.py +59 -0
  13. vllm_sr-0.1.0b2.dev20260115081807/cli/config_generator.py +353 -0
  14. vllm_sr-0.1.0b2.dev20260115081807/cli/consts.py +35 -0
  15. vllm_sr-0.1.0b2.dev20260115081807/cli/core.py +333 -0
  16. vllm_sr-0.1.0b2.dev20260115081807/cli/defaults.py +72 -0
  17. vllm_sr-0.1.0b2.dev20260115081807/cli/docker_cli.py +488 -0
  18. vllm_sr-0.1.0b2.dev20260115081807/cli/logo.py +30 -0
  19. vllm_sr-0.1.0b2.dev20260115081807/cli/main.py +277 -0
  20. vllm_sr-0.1.0b2.dev20260115081807/cli/merger.py +389 -0
  21. vllm_sr-0.1.0b2.dev20260115081807/cli/models.py +246 -0
  22. vllm_sr-0.1.0b2.dev20260115081807/cli/parser.py +201 -0
  23. vllm_sr-0.1.0b2.dev20260115081807/cli/templates/config.template.yaml +348 -0
  24. vllm_sr-0.1.0b2.dev20260115081807/cli/templates/envoy.template.yaml +161 -0
  25. vllm_sr-0.1.0b2.dev20260115081807/cli/templates/router-defaults.yaml +173 -0
  26. vllm_sr-0.1.0b2.dev20260115081807/cli/templates/tools_db.json +142 -0
  27. vllm_sr-0.1.0b2.dev20260115081807/cli/utils.py +149 -0
  28. vllm_sr-0.1.0b2.dev20260115081807/cli/validator.py +244 -0
  29. vllm_sr-0.1.0b2.dev20260115081807/pyproject.toml +57 -0
  30. vllm_sr-0.1.0b2.dev20260115081807/requirements.txt +7 -0
  31. vllm_sr-0.1.0b2.dev20260115081807/setup.cfg +4 -0
  32. vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/PKG-INFO +107 -0
  33. vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/SOURCES.txt +35 -0
  34. vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/dependency_links.txt +1 -0
  35. vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/entry_points.txt +2 -0
  36. vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/requires.txt +10 -0
  37. vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/top_level.txt +1 -0
@@ -0,0 +1,18 @@
1
+ # Include documentation
2
+ include README.md
3
+ include QUICKSTART.md
4
+ include PUBLISHING.md
5
+
6
+ # Include templates (now in cli package)
7
+ recursive-include cli/templates *.yaml
8
+ recursive-include cli/templates *.json
9
+
10
+ # Include requirements
11
+ include requirements.txt
12
+
13
+ # Exclude unnecessary files
14
+ global-exclude __pycache__
15
+ global-exclude *.py[co]
16
+ global-exclude .DS_Store
17
+ global-exclude *.egg-info
18
+
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.4
2
+ Name: vllm-sr
3
+ Version: 0.1.0b2.dev20260115081807
4
+ Summary: vLLM Semantic Router - Intelligent routing for Mixture-of-Models
5
+ Author: vLLM-SR Team
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/vllm-project/vllm-semantic-router
8
+ Project-URL: Documentation, https://github.com/vllm-project/vllm-semantic-router/blob/main/README.md
9
+ Project-URL: Repository, https://github.com/vllm-project/vllm-semantic-router
10
+ Project-URL: Issues, https://github.com/vllm-project/vllm-semantic-router/issues
11
+ Keywords: vllm,semantic-router,llm,routing,caching
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: click>=8.1.7
22
+ Requires-Dist: pyyaml>=6.0.2
23
+ Requires-Dist: jinja2>=3.1.4
24
+ Requires-Dist: requests>=2.31.0
25
+ Requires-Dist: pydantic>=2.0.0
26
+ Requires-Dist: huggingface_hub[cli]>=0.20.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=8.4.1; extra == "dev"
29
+ Requires-Dist: black>=22.0.0; extra == "dev"
30
+
31
+ # vLLM Semantic Router
32
+
33
+ Intelligent Router for Mixture-of-Models (MoM).
34
+
35
+ GitHub: https://github.com/vllm-project/semantic-router
36
+
37
+ ## Quick Start
38
+
39
+ ### Installation
40
+
41
+ ```bash
42
+ # Install from PyPI
43
+ pip install vllm-sr
44
+
45
+ # Or install from source (development)
46
+ cd src/vllm-sr
47
+ pip install -e .
48
+ ```
49
+
50
+ ### Usage
51
+
52
+ ```bash
53
+ # Initialize vLLM Semantic Router Configuration
54
+ vllm-sr init
55
+
56
+ # Start the router (includes dashboard)
57
+ vllm-sr serve
58
+
59
+ # Open dashboard in browser
60
+ vllm-sr dashboard
61
+
62
+ # View logs
63
+ vllm-sr logs router
64
+ vllm-sr logs envoy
65
+ vllm-sr logs dashboard
66
+
67
+ # Check status
68
+ vllm-sr status
69
+
70
+ # Stop
71
+ vllm-sr stop
72
+ ```
73
+
74
+ ## Features
75
+
76
+ - **Router**: Intelligent request routing based on intent classification
77
+ - **Envoy Proxy**: High-performance proxy with ext_proc integration
78
+ - **Dashboard**: Web UI for monitoring and testing (http://localhost:8700)
79
+ - **Metrics**: Prometheus metrics endpoint (http://localhost:9190/metrics)
80
+
81
+ ## Endpoints
82
+
83
+ After running `vllm-sr serve`, the following endpoints are available:
84
+
85
+ | Endpoint | Port | Description |
86
+ |----------|------|-------------|
87
+ | Dashboard | 8700 | Web UI for monitoring and Playground |
88
+ | API | 8888* | Chat completions API (configurable in config.yaml) |
89
+ | Metrics | 9190 | Prometheus metrics |
90
+ | gRPC | 50051 | Router gRPC (internal) |
91
+
92
+ *Default port, configurable via `listeners` in config.yaml
93
+
94
+ ## Configuration
95
+
96
+ ### File Descriptor Limits
97
+
98
+ The CLI automatically sets file descriptor limits to 65,536 for Envoy proxy. To customize:
99
+
100
+ ```bash
101
+ export VLLM_SR_NOFILE_LIMIT=100000 # Optional (min: 8192)
102
+ vllm-sr serve
103
+ ```
104
+
105
+ ## License
106
+
107
+ Apache 2.0
@@ -0,0 +1,77 @@
1
+ # vLLM Semantic Router
2
+
3
+ Intelligent Router for Mixture-of-Models (MoM).
4
+
5
+ GitHub: https://github.com/vllm-project/semantic-router
6
+
7
+ ## Quick Start
8
+
9
+ ### Installation
10
+
11
+ ```bash
12
+ # Install from PyPI
13
+ pip install vllm-sr
14
+
15
+ # Or install from source (development)
16
+ cd src/vllm-sr
17
+ pip install -e .
18
+ ```
19
+
20
+ ### Usage
21
+
22
+ ```bash
23
+ # Initialize vLLM Semantic Router Configuration
24
+ vllm-sr init
25
+
26
+ # Start the router (includes dashboard)
27
+ vllm-sr serve
28
+
29
+ # Open dashboard in browser
30
+ vllm-sr dashboard
31
+
32
+ # View logs
33
+ vllm-sr logs router
34
+ vllm-sr logs envoy
35
+ vllm-sr logs dashboard
36
+
37
+ # Check status
38
+ vllm-sr status
39
+
40
+ # Stop
41
+ vllm-sr stop
42
+ ```
43
+
44
+ ## Features
45
+
46
+ - **Router**: Intelligent request routing based on intent classification
47
+ - **Envoy Proxy**: High-performance proxy with ext_proc integration
48
+ - **Dashboard**: Web UI for monitoring and testing (http://localhost:8700)
49
+ - **Metrics**: Prometheus metrics endpoint (http://localhost:9190/metrics)
50
+
51
+ ## Endpoints
52
+
53
+ After running `vllm-sr serve`, the following endpoints are available:
54
+
55
+ | Endpoint | Port | Description |
56
+ |----------|------|-------------|
57
+ | Dashboard | 8700 | Web UI for monitoring and Playground |
58
+ | API | 8888* | Chat completions API (configurable in config.yaml) |
59
+ | Metrics | 9190 | Prometheus metrics |
60
+ | gRPC | 50051 | Router gRPC (internal) |
61
+
62
+ *Default port, configurable via `listeners` in config.yaml
63
+
64
+ ## Configuration
65
+
66
+ ### File Descriptor Limits
67
+
68
+ The CLI automatically sets file descriptor limits to 65,536 for Envoy proxy. To customize:
69
+
70
+ ```bash
71
+ export VLLM_SR_NOFILE_LIMIT=100000 # Optional (min: 8192)
72
+ vllm-sr serve
73
+ ```
74
+
75
+ ## License
76
+
77
+ Apache 2.0
@@ -0,0 +1,3 @@
1
+ """vLLM Semantic Router CLI package."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,9 @@
1
+ """CLI commands for vLLM Semantic Router."""
2
+
3
+ from .init import init_command
4
+ from .config import config_command
5
+
6
+ __all__ = [
7
+ "init_command",
8
+ "config_command",
9
+ ]
@@ -0,0 +1,91 @@
1
+ """Config command implementation."""
2
+
3
+ import sys
4
+ import yaml
5
+ from pathlib import Path
6
+
7
+ from cli.parser import parse_user_config, ConfigParseError
8
+ from cli.defaults import load_embedded_defaults, load_defaults
9
+ from cli.merger import merge_configs
10
+ from cli.validator import (
11
+ validate_user_config,
12
+ validate_merged_config,
13
+ print_validation_errors,
14
+ )
15
+ from cli.config_generator import generate_envoy_config_from_user_config
16
+ from cli.utils import getLogger
17
+
18
+ log = getLogger(__name__)
19
+
20
+
21
+ def config_command(config_type: str, config_path: str = "config.yaml"):
22
+ """
23
+ Print generated configuration.
24
+
25
+ Args:
26
+ config_type: Type of config to print ('envoy' or 'router')
27
+ config_path: Path to user config.yaml (default: config.yaml)
28
+ """
29
+ if config_type not in ["envoy", "router"]:
30
+ log.error(f"Invalid config type: {config_type}")
31
+ log.error("Must be 'envoy' or 'router'")
32
+ sys.exit(1)
33
+
34
+ # Check if config file exists
35
+ if not Path(config_path).exists():
36
+ log.error(f"Config file not found: {config_path}")
37
+ log.error("Run 'vllm-sr init' to create a config file")
38
+ sys.exit(1)
39
+
40
+ # Parse user config
41
+ try:
42
+ user_config = parse_user_config(config_path)
43
+ except ConfigParseError as e:
44
+ log.error(f"Failed to parse configuration: {e}")
45
+ sys.exit(1)
46
+
47
+ # Validate user config
48
+ errors = validate_user_config(user_config)
49
+ if errors:
50
+ log.error("Configuration validation failed:")
51
+ print_validation_errors(errors)
52
+ sys.exit(1)
53
+
54
+ if config_type == "router":
55
+ # Generate router config (use local defaults if available)
56
+ defaults = load_defaults(".vllm-sr")
57
+ merged = merge_configs(user_config, defaults)
58
+
59
+ # Validate merged config
60
+ errors = validate_merged_config(merged)
61
+ if errors:
62
+ log.error("Merged configuration validation failed:")
63
+ print_validation_errors(errors)
64
+ sys.exit(1)
65
+
66
+ # Print router config as YAML
67
+ print(yaml.dump(merged, default_flow_style=False, sort_keys=False))
68
+
69
+ elif config_type == "envoy":
70
+ # Generate envoy config
71
+ try:
72
+ # Generate to a temporary string
73
+ import tempfile
74
+
75
+ with tempfile.NamedTemporaryFile(
76
+ mode="w", suffix=".yaml", delete=False
77
+ ) as f:
78
+ temp_path = f.name
79
+
80
+ generate_envoy_config_from_user_config(user_config, temp_path)
81
+
82
+ # Read and print
83
+ with open(temp_path, "r") as f:
84
+ print(f.read())
85
+
86
+ # Clean up
87
+ Path(temp_path).unlink()
88
+
89
+ except Exception as e:
90
+ log.error(f"Failed to generate Envoy config: {e}")
91
+ sys.exit(1)
@@ -0,0 +1,73 @@
1
+ """Generate command implementation."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ from cli.commands.serve import (
7
+ generate_router_config,
8
+ copy_defaults_reference,
9
+ ensure_output_directory,
10
+ DEFAULT_OUTPUT_DIR,
11
+ )
12
+ from cli.parser import parse_user_config, ConfigParseError
13
+ from cli.config_generator import generate_envoy_config_from_user_config
14
+ from cli.utils import getLogger
15
+
16
+ log = getLogger(__name__)
17
+
18
+
19
+ def generate_command(
20
+ config_path: str, output_dir: str = DEFAULT_OUTPUT_DIR, force: bool = False
21
+ ):
22
+ """
23
+ Generate configurations without starting services.
24
+
25
+ Args:
26
+ config_path: Path to user config.yaml
27
+ output_dir: Output directory for generated configs
28
+ force: Force overwrite existing files
29
+ """
30
+ log.info("=" * 60)
31
+ log.info("vLLM Semantic Router - Generate Configurations")
32
+ log.info("=" * 60)
33
+
34
+ # Ensure output directory exists
35
+ output_path = ensure_output_directory(output_dir)
36
+
37
+ # Parse user config (needed for Envoy generation)
38
+ try:
39
+ user_config = parse_user_config(config_path)
40
+ except ConfigParseError as e:
41
+ log.error(f"Failed to parse configuration: {e}")
42
+ sys.exit(1)
43
+
44
+ # Generate router config
45
+ router_config_path = generate_router_config(config_path, output_dir, force=force)
46
+
47
+ # Copy defaults for reference
48
+ defaults_path = copy_defaults_reference(output_dir)
49
+
50
+ # Generate Envoy config
51
+ envoy_config_path = None
52
+ try:
53
+ envoy_output = output_path / "envoy-config.yaml"
54
+ envoy_config_path = generate_envoy_config_from_user_config(
55
+ user_config, str(envoy_output)
56
+ )
57
+ except Exception as e:
58
+ log.warning(f"Failed to generate Envoy config: {e}")
59
+ log.warning("Continuing without Envoy config...")
60
+
61
+ log.info("=" * 60)
62
+ log.info("✓ Configurations generated successfully")
63
+ log.info(f" Output directory: {output_path.absolute()}")
64
+ log.info(f" Router config: {router_config_path.name}")
65
+ if envoy_config_path:
66
+ log.info(f" Envoy config: {envoy_config_path.name}")
67
+ log.info(f" Defaults reference: {defaults_path.name}")
68
+ log.info("=" * 60)
69
+ log.info("\nYou can now:")
70
+ log.info(f" • Edit {router_config_path} to customize system settings")
71
+ if envoy_config_path:
72
+ log.info(f" • Edit {envoy_config_path} to customize Envoy settings")
73
+ log.info(f" • Start service with: vllm-sr serve {config_path}")
@@ -0,0 +1,96 @@
1
+ """Init command implementation."""
2
+
3
+ import os
4
+ import shutil
5
+ import sys
6
+ from pathlib import Path
7
+ from cli.utils import getLogger
8
+
9
+ log = getLogger(__name__)
10
+
11
+
12
+ def get_templates_dir():
13
+ """
14
+ Get the templates directory path.
15
+
16
+ Templates are now in cli/templates/ directory.
17
+ """
18
+ # Get cli package directory
19
+ cli_dir = Path(__file__).parent.parent
20
+ templates_dir = cli_dir / "templates"
21
+
22
+ return templates_dir if templates_dir.exists() else None
23
+
24
+
25
+ def init_command(force: bool = False):
26
+ """
27
+ Initialize vLLM Semantic Router configuration.
28
+
29
+ Creates:
30
+ - config.yaml from config.template.yaml
31
+ - .vllm-sr/ directory with template files
32
+
33
+ Args:
34
+ force: Force overwrite existing files
35
+ """
36
+ log.info("=" * 60)
37
+ log.info("vLLM Semantic Router - Initialize Configuration")
38
+ log.info("=" * 60)
39
+
40
+ # Get current directory
41
+ current_dir = Path.cwd()
42
+ config_file = current_dir / "config.yaml"
43
+ vllm_sr_dir = current_dir / ".vllm-sr"
44
+
45
+ # Get templates directory
46
+ templates_dir = get_templates_dir()
47
+
48
+ if templates_dir is None or not templates_dir.exists():
49
+ log.error(f"Templates directory not found: {templates_dir}")
50
+ log.error("Please ensure vllm-sr is installed correctly.")
51
+ return False
52
+
53
+ # Copy config.template.yaml to config.yaml
54
+ template_config = templates_dir / "config.template.yaml"
55
+ if not template_config.exists():
56
+ log.error(f"Config template not found: {template_config}")
57
+ return False
58
+
59
+ if config_file.exists():
60
+ log.warning(f"config.yaml already exists, overwriting...")
61
+
62
+ shutil.copy2(template_config, config_file)
63
+ log.info(f"✓ Created config.yaml")
64
+
65
+ # Create .vllm-sr directory
66
+ if vllm_sr_dir.exists():
67
+ log.warning(f".vllm-sr/ directory already exists, overwriting...")
68
+ shutil.rmtree(vllm_sr_dir)
69
+
70
+ vllm_sr_dir.mkdir(exist_ok=True)
71
+ log.info(f"✓ Created .vllm-sr/ directory")
72
+
73
+ # Copy all template files to .vllm-sr/
74
+ copied_files = []
75
+ for template_file in templates_dir.iterdir():
76
+ if template_file.is_file() and template_file.name != "config.template.yaml":
77
+ dest_file = vllm_sr_dir / template_file.name
78
+ shutil.copy2(template_file, dest_file)
79
+ copied_files.append(template_file.name)
80
+ log.info(f" • Copied {template_file.name}")
81
+
82
+ log.info("=" * 60)
83
+ log.info("✓ Initialization complete!")
84
+ log.info("")
85
+ log.info("Created files:")
86
+ log.info(f" • config.yaml")
87
+ log.info(f" • .vllm-sr/ ({len(copied_files)} files)")
88
+ log.info("")
89
+ log.info("Next steps:")
90
+ log.info(" 1. Edit config.yaml to configure your setup")
91
+ log.info(" Or use the dashboard for visual configuration")
92
+ log.info(" 2. Start service: vllm-sr serve")
93
+ log.info(" 3. Open dashboard: http://localhost:8700")
94
+ log.info("=" * 60)
95
+
96
+ return True
@@ -0,0 +1,206 @@
1
+ """Serve command implementation."""
2
+
3
+ import os
4
+ import sys
5
+ import yaml
6
+ from pathlib import Path
7
+
8
+ from cli.parser import parse_user_config, ConfigParseError
9
+ from cli.defaults import load_embedded_defaults, get_defaults_yaml, load_defaults
10
+ from cli.merger import merge_configs
11
+ from cli.validator import (
12
+ validate_user_config,
13
+ validate_merged_config,
14
+ print_validation_errors,
15
+ )
16
+ from cli.config_generator import generate_envoy_config_from_user_config
17
+ from cli.utils import getLogger
18
+
19
+ log = getLogger(__name__)
20
+
21
+ DEFAULT_OUTPUT_DIR = ".vllm-sr"
22
+
23
+
24
+ def ensure_output_directory(output_dir: str) -> Path:
25
+ """
26
+ Ensure output directory exists.
27
+
28
+ Args:
29
+ output_dir: Output directory path
30
+
31
+ Returns:
32
+ Path: Output directory path object
33
+ """
34
+ output_path = Path(output_dir)
35
+ output_path.mkdir(parents=True, exist_ok=True)
36
+ return output_path
37
+
38
+
39
+ def generate_router_config(
40
+ config_path: str, output_dir: str = DEFAULT_OUTPUT_DIR, force: bool = False
41
+ ) -> Path:
42
+ """
43
+ Generate router configuration from user config.
44
+
45
+ Args:
46
+ config_path: Path to user config.yaml
47
+ output_dir: Output directory
48
+ force: Force regeneration even if file exists
49
+
50
+ Returns:
51
+ Path: Path to generated router config
52
+ """
53
+ output_path = ensure_output_directory(output_dir)
54
+ router_config_path = output_path / "router-config.yaml"
55
+
56
+ # Check if router config already exists
57
+ if router_config_path.exists() and not force:
58
+ log.info(f"Using existing {router_config_path}")
59
+ log.info(f" (Use --regenerate to recreate from {config_path})")
60
+ return router_config_path
61
+
62
+ log.info(f"Generating {router_config_path}...")
63
+
64
+ # Parse user config
65
+ try:
66
+ user_config = parse_user_config(config_path)
67
+ except ConfigParseError as e:
68
+ log.error(f"Failed to parse configuration: {e}")
69
+ sys.exit(1)
70
+
71
+ # Validate user config
72
+ errors = validate_user_config(user_config)
73
+ if errors:
74
+ print_validation_errors(errors)
75
+ sys.exit(1)
76
+
77
+ # Load defaults (prefer local router-defaults.yaml if it exists)
78
+ defaults = load_defaults(output_dir)
79
+
80
+ # Log which defaults were used
81
+ local_defaults_path = Path(output_dir) / "router-defaults.yaml"
82
+ if local_defaults_path.exists():
83
+ log.info(f" Using local defaults: {local_defaults_path}")
84
+ else:
85
+ log.info(f" Using embedded defaults")
86
+
87
+ # Merge configs
88
+ merged = merge_configs(user_config, defaults)
89
+
90
+ # Validate merged config
91
+ errors = validate_merged_config(merged)
92
+ if errors:
93
+ print_validation_errors(errors)
94
+ sys.exit(1)
95
+
96
+ # Write router config
97
+ with open(router_config_path, "w") as f:
98
+ yaml.dump(merged, f, default_flow_style=False, sort_keys=False)
99
+
100
+ log.info(f"✓ Generated {router_config_path}")
101
+
102
+ return router_config_path
103
+
104
+
105
+ def copy_defaults_reference(output_dir: str) -> Path:
106
+ """
107
+ Copy embedded defaults to output directory for reference.
108
+
109
+ Will NOT overwrite existing router-defaults.yaml to preserve user modifications.
110
+
111
+ Args:
112
+ output_dir: Output directory
113
+
114
+ Returns:
115
+ Path: Path to defaults reference file
116
+ """
117
+ output_path = Path(output_dir)
118
+ defaults_path = output_path / "router-defaults.yaml"
119
+
120
+ if defaults_path.exists():
121
+ log.info(f"Using existing {defaults_path} (preserving user modifications)")
122
+ return defaults_path
123
+
124
+ log.info(f"Copying router-defaults.yaml (for reference)...")
125
+
126
+ with open(defaults_path, "w") as f:
127
+ f.write(get_defaults_yaml())
128
+
129
+ log.info(f"✓ Copied {defaults_path}")
130
+
131
+ return defaults_path
132
+
133
+
134
+ def serve_command(
135
+ config_path: str,
136
+ output_dir: str = DEFAULT_OUTPUT_DIR,
137
+ regenerate: bool = False,
138
+ router_config: str = None,
139
+ envoy_config: str = None,
140
+ ):
141
+ """
142
+ Start vLLM Semantic Router service.
143
+
144
+ Args:
145
+ config_path: Path to user config.yaml
146
+ output_dir: Output directory for generated configs
147
+ regenerate: Force regenerate router config
148
+ router_config: Custom router config path (bypasses generation)
149
+ envoy_config: Custom Envoy config path (bypasses generation)
150
+ """
151
+ log.info("=" * 60)
152
+ log.info("vLLM Semantic Router - Starting Service")
153
+ log.info("=" * 60)
154
+
155
+ # Ensure output directory exists
156
+ output_path = ensure_output_directory(output_dir)
157
+
158
+ # Parse user config (needed for Envoy generation)
159
+ try:
160
+ user_config = parse_user_config(config_path)
161
+ except ConfigParseError as e:
162
+ log.error(f"Failed to parse configuration: {e}")
163
+ sys.exit(1)
164
+
165
+ # Generate or use existing router config
166
+ if router_config:
167
+ log.info(f"Using custom router config: {router_config}")
168
+ router_config_path = Path(router_config)
169
+ else:
170
+ router_config_path = generate_router_config(
171
+ config_path, output_dir, force=regenerate
172
+ )
173
+
174
+ # Copy defaults for reference
175
+ copy_defaults_reference(output_dir)
176
+
177
+ # Generate Envoy config
178
+ envoy_config_path = None
179
+ if envoy_config:
180
+ log.info(f"Using custom Envoy config: {envoy_config}")
181
+ envoy_config_path = Path(envoy_config)
182
+ else:
183
+ try:
184
+ envoy_output = output_path / "envoy-config.yaml"
185
+ envoy_config_path = generate_envoy_config_from_user_config(
186
+ user_config, str(envoy_output)
187
+ )
188
+ except Exception as e:
189
+ log.warning(f"Failed to generate Envoy config: {e}")
190
+ log.warning("Continuing without Envoy config...")
191
+
192
+ # TODO: Start services
193
+
194
+ log.info("=" * 60)
195
+ log.info("✓ Configuration generated successfully")
196
+ log.info(f" Router config: {router_config_path}")
197
+ if envoy_config_path:
198
+ log.info(f" Envoy config: {envoy_config_path}")
199
+ log.info(f" Output directory: {output_dir}")
200
+ log.info("=" * 60)
201
+
202
+ # For now, just show what would happen
203
+ log.info("\nNext steps (to be implemented):")
204
+ log.info(" 1. Start Envoy proxy")
205
+ log.info(" 2. Start Router service")
206
+ log.info(" 3. Wait for health checks")