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.
- vllm_sr-0.1.0b2.dev20260115081807/MANIFEST.in +18 -0
- vllm_sr-0.1.0b2.dev20260115081807/PKG-INFO +107 -0
- vllm_sr-0.1.0b2.dev20260115081807/README.md +77 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/__init__.py +3 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/commands/__init__.py +9 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/commands/config.py +91 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/commands/generate.py +73 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/commands/init.py +96 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/commands/serve.py +206 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/commands/show_config.py +146 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/commands/show_defaults.py +29 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/commands/validate.py +59 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/config_generator.py +353 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/consts.py +35 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/core.py +333 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/defaults.py +72 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/docker_cli.py +488 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/logo.py +30 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/main.py +277 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/merger.py +389 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/models.py +246 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/parser.py +201 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/templates/config.template.yaml +348 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/templates/envoy.template.yaml +161 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/templates/router-defaults.yaml +173 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/templates/tools_db.json +142 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/utils.py +149 -0
- vllm_sr-0.1.0b2.dev20260115081807/cli/validator.py +244 -0
- vllm_sr-0.1.0b2.dev20260115081807/pyproject.toml +57 -0
- vllm_sr-0.1.0b2.dev20260115081807/requirements.txt +7 -0
- vllm_sr-0.1.0b2.dev20260115081807/setup.cfg +4 -0
- vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/PKG-INFO +107 -0
- vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/SOURCES.txt +35 -0
- vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/dependency_links.txt +1 -0
- vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/entry_points.txt +2 -0
- vllm_sr-0.1.0b2.dev20260115081807/vllm_sr.egg-info/requires.txt +10 -0
- 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,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")
|