Implement common ParseCommand interface

This commit is contained in:
2025-10-25 18:41:46 +02:00
parent 0a7420c9f9
commit bd6436840e
8 changed files with 36 additions and 27 deletions

View File

@@ -23,6 +23,7 @@ type backend interface {
SetPort(int)
GetHost() string
Validate() error
ParseCommand(string) (any, error)
}
var backendConstructors = map[BackendType]func() backend{

View File

@@ -378,19 +378,19 @@ func (o *LlamaServerOptions) BuildDockerArgs() []string {
return o.BuildCommandArgs()
}
// ParseLlamaCommand parses a llama-server command string into LlamaServerOptions
// ParseCommand parses a llama-server command string into LlamaServerOptions
// Supports multiple formats:
// 1. Full command: "llama-server --model file.gguf"
// 2. Full path: "/usr/local/bin/llama-server --model file.gguf"
// 3. Args only: "--model file.gguf --gpu-layers 32"
// 4. Multiline commands with backslashes
func ParseLlamaCommand(command string) (*LlamaServerOptions, error) {
func (o *LlamaServerOptions) ParseCommand(command string) (any, error) {
executableNames := []string{"llama-server"}
var subcommandNames []string // Llama has no subcommands
// Use package-level llamaMultiValuedFlags variable
var llamaOptions LlamaServerOptions
if err := ParseCommand(command, executableNames, subcommandNames, llamaMultiValuedFlags, &llamaOptions); err != nil {
if err := parseCommand(command, executableNames, subcommandNames, llamaMultiValuedFlags, &llamaOptions); err != nil {
return nil, err
}

View File

@@ -385,7 +385,9 @@ func TestParseLlamaCommand(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := backends.ParseLlamaCommand(tt.command)
var opts backends.LlamaServerOptions
resultAny, err := opts.ParseCommand(tt.command)
result, _ := resultAny.(*backends.LlamaServerOptions)
if tt.expectErr {
if err == nil {
@@ -413,7 +415,9 @@ func TestParseLlamaCommand(t *testing.T) {
func TestParseLlamaCommandArrays(t *testing.T) {
command := "llama-server --model test.gguf --lora adapter1.bin --lora=adapter2.bin"
result, err := backends.ParseLlamaCommand(command)
var opts backends.LlamaServerOptions
resultAny, err := opts.ParseCommand(command)
result, _ := resultAny.(*backends.LlamaServerOptions)
if err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@@ -70,19 +70,19 @@ func (o *MlxServerOptions) BuildDockerArgs() []string {
return []string{}
}
// ParseMlxCommand parses a mlx_lm.server command string into MlxServerOptions
// ParseCommand parses a mlx_lm.server command string into MlxServerOptions
// Supports multiple formats:
// 1. Full command: "mlx_lm.server --model model/path"
// 2. Full path: "/usr/local/bin/mlx_lm.server --model model/path"
// 3. Args only: "--model model/path --host 0.0.0.0"
// 4. Multiline commands with backslashes
func ParseMlxCommand(command string) (*MlxServerOptions, error) {
func (o *MlxServerOptions) ParseCommand(command string) (any, error) {
executableNames := []string{"mlx_lm.server"}
var subcommandNames []string // MLX has no subcommands
multiValuedFlags := map[string]bool{} // MLX has no multi-valued flags
var mlxOptions MlxServerOptions
if err := ParseCommand(command, executableNames, subcommandNames, multiValuedFlags, &mlxOptions); err != nil {
if err := parseCommand(command, executableNames, subcommandNames, multiValuedFlags, &mlxOptions); err != nil {
return nil, err
}

View File

@@ -96,7 +96,9 @@ func TestParseMlxCommand(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := backends.ParseMlxCommand(tt.command)
var opts backends.MlxServerOptions
resultAny, err := opts.ParseCommand(tt.command)
result, _ := resultAny.(*backends.MlxServerOptions)
if tt.expectErr {
if err == nil {

View File

@@ -9,8 +9,8 @@ import (
"strings"
)
// ParseCommand parses a command string into a target struct
func ParseCommand(command string, executableNames []string, subcommandNames []string, multiValuedFlags map[string]bool, target any) error {
// parseCommand parses a command string into a target struct
func parseCommand(command string, executableNames []string, subcommandNames []string, multiValuedFlags map[string]bool, target any) error {
// Normalize multiline commands
command = normalizeCommand(command)
if command == "" {

View File

@@ -202,14 +202,14 @@ func (o *VllmServerOptions) BuildDockerArgs() []string {
return args
}
// ParseVllmCommand parses a vLLM serve command string into VllmServerOptions
// ParseCommand parses a vLLM serve command string into VllmServerOptions
// Supports multiple formats:
// 1. Full command: "vllm serve --model MODEL_NAME --other-args"
// 2. Full path: "/usr/local/bin/vllm serve --model MODEL_NAME"
// 3. Serve only: "serve --model MODEL_NAME --other-args"
// 4. Args only: "--model MODEL_NAME --other-args"
// 5. Multiline commands with backslashes
func ParseVllmCommand(command string) (*VllmServerOptions, error) {
func (o *VllmServerOptions) ParseCommand(command string) (any, error) {
executableNames := []string{"vllm"}
subcommandNames := []string{"serve"}
multiValuedFlags := map[string]bool{
@@ -223,7 +223,7 @@ func ParseVllmCommand(command string) (*VllmServerOptions, error) {
}
var vllmOptions VllmServerOptions
if err := ParseCommand(command, executableNames, subcommandNames, multiValuedFlags, &vllmOptions); err != nil {
if err := parseCommand(command, executableNames, subcommandNames, multiValuedFlags, &vllmOptions); err != nil {
return nil, err
}

View File

@@ -92,7 +92,9 @@ func TestParseVllmCommand(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := backends.ParseVllmCommand(tt.command)
var opts backends.VllmServerOptions
resultAny, err := opts.ParseCommand(tt.command)
result, _ := resultAny.(*backends.VllmServerOptions)
if tt.expectErr {
if err == nil {