Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion pkg/cmd/dev/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,28 @@ func runDev(ctx context.Context, options *DevStartOptions) error {
return err
}

// Detect and collect lora-adapter parts
var loraPaths []string
for _, part := range kitfile.Model.Parts {
if strings.EqualFold(part.Type, "lora-adapter") {
if part.Path == "" {
continue
}
partAbsPath, _, err := filesystem.VerifySubpath(options.contextDir, part.Path)
if err != nil {
output.Debugf("Skipping lora-adapter: %v", err)
continue
}
loraPath, err := findLoraAdapterFile(partAbsPath)
if err != nil {
output.Debugf("Skipping lora-adapter: %v", err)
continue
}
output.Infof("Found lora-adapter: %s", loraPath)
loraPaths = append(loraPaths, loraPath)
}
}

llmHarness := &harness.LLMHarness{}
llmHarness.Host = options.host
llmHarness.Port = options.port
Expand All @@ -93,7 +115,7 @@ func runDev(ctx context.Context, options *DevStartOptions) error {
return err
}

if err := llmHarness.Start(modelPath); err != nil {
if err := llmHarness.Start(modelPath, loraPaths); err != nil {
return err
}

Expand Down Expand Up @@ -170,6 +192,26 @@ func findModelFile(absPath string) (string, error) {
return modelPath, nil
}

// findLoraAdapterFile validates a lora adapter path.
// The path must point to a regular file.
func findLoraAdapterFile(absPath string) (string, error) {
Comment thread
rishi-jat marked this conversation as resolved.
stat, err := os.Lstat(absPath)
if err != nil {
return "", err
}

if !stat.Mode().IsRegular() {
return "", fmt.Errorf("lora adapter path must be a regular .gguf file: %s", absPath)
}

if !strings.HasSuffix(strings.ToLower(absPath), ".gguf") {
return "", fmt.Errorf("lora adapter file must be a .gguf file: %s", absPath)
}

output.Debugf("Found lora adapter path at %s", absPath)
return absPath, nil
}

// extractModelKitToCache extracts a ModelKit reference to a cache directory
// using the unpack library with model filter
func extractModelKitToCache(ctx context.Context, options *DevStartOptions) error {
Expand Down
39 changes: 23 additions & 16 deletions pkg/lib/harness/llm-harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (harness *LLMHarness) Init() error {
return nil
}

func (harness *LLMHarness) Start(modelPath string) (err error) {
func (harness *LLMHarness) Start(modelPath string, loraPaths []string) (err error) {

harnessPath := constants.HarnessPath(harness.ConfigHome)
pidFile := filepath.Join(harnessPath, constants.HarnessProcessFile)
Expand All @@ -85,24 +85,31 @@ func (harness *LLMHarness) Start(modelPath string) (err error) {

uiHome := filepath.Join(harnessPath, "ui")
output.Debugf("model path is %s", modelPath)
for _, loraPath := range loraPaths {
output.Debugf("lora adapter path is %s", loraPath)
}
var cmd *exec.Cmd
args := []string{
"--server",
"--model", modelPath,
"--host", harness.Host,
"--port", fmt.Sprintf("%d", harness.Port),
"--path", uiHome,
"--gpu", "AUTO",
"--nobrowser",
"--unsecure",
}
for _, loraPath := range loraPaths {
args = append(args, "--lora", loraPath)
}

if runtime.GOOS == "windows" {
cmd = exec.Command(
"./llamafile.exe",
"--server",
"--model", modelPath,
"--host", harness.Host,
"--port", fmt.Sprintf("%d", harness.Port),
"--path", uiHome,
"--gpu", "AUTO",
"--nobrowser",
"--unsecure",
)
cmd = exec.Command("./llamafile.exe", args...)
} else {
cmd = exec.Command("sh", "-c",
fmt.Sprintf("./llamafile --server --model %s --host %s --port %d --path %s --gpu AUTO --nobrowser --unsecure",
modelPath, harness.Host, harness.Port, uiHome),
)
// Run through sh -c for APE compatibility, while passing all user-controlled
// values as positional args to avoid shell interpolation and injection.
shellArgs := append([]string{"-c", "exec ./llamafile \"$@\"", "llamafile"}, args...)
cmd = exec.Command("sh", shellArgs...)
}

cmd.Dir = harnessPath
Expand Down