mirror of
https://github.com/lordmathis/llamactl.git
synced 2025-11-06 09:04:27 +00:00
Fix vllm command parsing
This commit is contained in:
@@ -17,8 +17,8 @@ func ParseCommand(command string, executableNames []string, subcommandNames []st
|
|||||||
return fmt.Errorf("command cannot be empty")
|
return fmt.Errorf("command cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract arguments
|
// Extract arguments and positional model
|
||||||
args, err := extractArgs(command, executableNames, subcommandNames)
|
args, modelFromPositional, err := extractArgs(command, executableNames, subcommandNames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,13 @@ func ParseCommand(command string, executableNames []string, subcommandNames []st
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we found a positional model and no --model flag was provided, set the model
|
||||||
|
if modelFromPositional != "" {
|
||||||
|
if _, hasModelFlag := options["model"]; !hasModelFlag {
|
||||||
|
options["model"] = modelFromPositional
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Convert to target struct via JSON
|
// Convert to target struct via JSON
|
||||||
jsonData, err := json.Marshal(options)
|
jsonData, err := json.Marshal(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -51,15 +58,16 @@ func normalizeCommand(command string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// extractArgs extracts arguments from command, removing executable and subcommands
|
// extractArgs extracts arguments from command, removing executable and subcommands
|
||||||
func extractArgs(command string, executableNames []string, subcommandNames []string) ([]string, error) {
|
// Returns: args, modelFromPositional, error
|
||||||
|
func extractArgs(command string, executableNames []string, subcommandNames []string) ([]string, string, error) {
|
||||||
// Check for unterminated quotes
|
// Check for unterminated quotes
|
||||||
if strings.Count(command, `"`)%2 != 0 || strings.Count(command, `'`)%2 != 0 {
|
if strings.Count(command, `"`)%2 != 0 || strings.Count(command, `'`)%2 != 0 {
|
||||||
return nil, fmt.Errorf("unterminated quoted string")
|
return nil, "", fmt.Errorf("unterminated quoted string")
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens := strings.Fields(command)
|
tokens := strings.Fields(command)
|
||||||
if len(tokens) == 0 {
|
if len(tokens) == 0 {
|
||||||
return nil, fmt.Errorf("no tokens found")
|
return nil, "", fmt.Errorf("no tokens found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip executable
|
// Skip executable
|
||||||
@@ -104,7 +112,16 @@ func extractArgs(command string, executableNames []string, subcommandNames []str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokens[start:], nil
|
args := tokens[start:]
|
||||||
|
|
||||||
|
// Extract first positional argument (model) if present and not a flag
|
||||||
|
var modelFromPositional string
|
||||||
|
if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
|
||||||
|
modelFromPositional = args[0]
|
||||||
|
args = args[1:] // Remove the model from args to process remaining flags
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, modelFromPositional, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseFlags parses command line flags into a map
|
// parseFlags parses command line flags into a map
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ func TestParseVllmCommand(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "basic vllm serve command",
|
name: "basic vllm serve command",
|
||||||
command: "vllm serve --model microsoft/DialoGPT-medium",
|
command: "vllm serve microsoft/DialoGPT-medium",
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "serve only command",
|
name: "serve only command",
|
||||||
command: "serve --model microsoft/DialoGPT-medium",
|
command: "serve microsoft/DialoGPT-medium",
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "args only",
|
name: "positional model with flags",
|
||||||
command: "--model microsoft/DialoGPT-medium --tensor-parallel-size 2",
|
command: "vllm serve microsoft/DialoGPT-medium --tensor-parallel-size 2",
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "model with path",
|
||||||
|
command: "vllm serve /path/to/model --gpu-memory-utilization 0.8",
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -34,7 +39,7 @@ func TestParseVllmCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unterminated quote",
|
name: "unterminated quote",
|
||||||
command: `vllm serve --model "unterminated`,
|
command: `vllm serve "unterminated`,
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -63,7 +68,7 @@ func TestParseVllmCommand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParseVllmCommandValues(t *testing.T) {
|
func TestParseVllmCommandValues(t *testing.T) {
|
||||||
command := "vllm serve --model test-model --tensor-parallel-size 4 --gpu-memory-utilization 0.8 --enable-log-outputs"
|
command := "vllm serve test-model --tensor-parallel-size 4 --gpu-memory-utilization 0.8 --enable-log-outputs"
|
||||||
result, err := vllm.ParseVllmCommand(command)
|
result, err := vllm.ParseVllmCommand(command)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user