From 154b754aff9fad718bf12173645a92b0fad96137 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Tue, 16 Sep 2025 21:39:08 +0200 Subject: [PATCH] Add MLX command parsing and routing support --- pkg/manager/operations.go | 10 ++++++- pkg/server/handlers.go | 55 +++++++++++++++++++++++++++++++++++++++ pkg/server/routes.go | 3 +++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/pkg/manager/operations.go b/pkg/manager/operations.go index 6f65680..1354481 100644 --- a/pkg/manager/operations.go +++ b/pkg/manager/operations.go @@ -62,7 +62,7 @@ func (im *instanceManager) CreateInstance(name string, options *instance.CreateI im.onStatusChange(name, oldStatus, newStatus) } - inst := instance.NewInstance(name, &im.instancesConfig, options, statusCallback) + inst := instance.NewInstance(name, &im.backendsConfig, &im.instancesConfig, options, statusCallback) im.instances[inst.Name] = inst if err := im.persistInstance(inst); err != nil { @@ -260,6 +260,10 @@ func (im *instanceManager) getPortFromOptions(options *instance.CreateInstanceOp if options.LlamaServerOptions != nil { return options.LlamaServerOptions.Port } + case backends.BackendTypeMlxLm: + if options.MlxServerOptions != nil { + return options.MlxServerOptions.Port + } } return 0 } @@ -271,6 +275,10 @@ func (im *instanceManager) setPortInOptions(options *instance.CreateInstanceOpti if options.LlamaServerOptions != nil { options.LlamaServerOptions.Port = port } + case backends.BackendTypeMlxLm: + if options.MlxServerOptions != nil { + options.MlxServerOptions.Port = port + } } } diff --git a/pkg/server/handlers.go b/pkg/server/handlers.go index e5e2eb5..c4932b2 100644 --- a/pkg/server/handlers.go +++ b/pkg/server/handlers.go @@ -7,6 +7,7 @@ import ( "io" "llamactl/pkg/backends" "llamactl/pkg/backends/llamacpp" + "llamactl/pkg/backends/mlx" "llamactl/pkg/config" "llamactl/pkg/instance" "llamactl/pkg/manager" @@ -684,3 +685,57 @@ func (h *Handler) ParseLlamaCommand() http.HandlerFunc { } } } + +// ParseMlxCommand godoc +// @Summary Parse mlx_lm.server command +// @Description Parses MLX-LM server command string into instance options +// @Tags backends +// @Security ApiKeyAuth +// @Accept json +// @Produce json +// @Param request body ParseCommandRequest true "Command to parse" +// @Success 200 {object} instance.CreateInstanceOptions "Parsed options" +// @Failure 400 {object} map[string]string "Invalid request or command" +// @Router /backends/mlx/parse-command [post] +func (h *Handler) ParseMlxCommand() http.HandlerFunc { + type errorResponse struct { + Error string `json:"error"` + Details string `json:"details,omitempty"` + } + writeError := func(w http.ResponseWriter, status int, code, details string) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(status) + _ = json.NewEncoder(w).Encode(errorResponse{Error: code, Details: details}) + } + return func(w http.ResponseWriter, r *http.Request) { + var req ParseCommandRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + writeError(w, http.StatusBadRequest, "invalid_request", "Invalid JSON body") + return + } + + if strings.TrimSpace(req.Command) == "" { + writeError(w, http.StatusBadRequest, "invalid_command", "Command cannot be empty") + return + } + + mlxOptions, err := mlx.ParseMlxCommand(req.Command) + if err != nil { + writeError(w, http.StatusBadRequest, "parse_error", err.Error()) + return + } + + // Currently only support mlx_lm backend type + backendType := backends.BackendTypeMlxLm + + options := &instance.CreateInstanceOptions{ + BackendType: backendType, + MlxServerOptions: mlxOptions, + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(options); err != nil { + writeError(w, http.StatusInternalServerError, "encode_error", err.Error()) + } + } +} diff --git a/pkg/server/routes.go b/pkg/server/routes.go index 0f2568d..aa31e1f 100644 --- a/pkg/server/routes.go +++ b/pkg/server/routes.go @@ -55,6 +55,9 @@ func SetupRouter(handler *Handler) *chi.Mux { r.Route("/llama-cpp", func(r chi.Router) { r.Post("/parse-command", handler.ParseLlamaCommand()) }) + r.Route("/mlx", func(r chi.Router) { + r.Post("/parse-command", handler.ParseMlxCommand()) + }) }) // Instance management endpoints