Skip to content

Conversation

@ericcurtin
Copy link
Contributor

@ericcurtin ericcurtin commented Oct 15, 2025

Support ollama runner commands with GPU variants

Add ollama model detection and runner initialization

Add comprehensive tests for ollama functionality

Add comprehensive documentation for ollama integration

Summary by Sourcery

Add support for ollama as an alternative model runner, including a new --ollama flag across runner commands, GPU variant handling, and automatic container/image/volume lifecycle management

New Features:

  • Introduce --ollama flag to install, start, stop, restart, reinstall, and uninstall commands to operate an ollama runner
  • Automatically detect and initialize an ollama runner container with image pull, storage volume creation, and runtime readiness checks
  • Support ollama-specific GPU variants with auto-detection and explicit CUDA/ROCm selection

Enhancements:

  • Refactor container and volume management to use a runnerType label and consolidate image/volume logic into shared internal functions
  • Extend pull and run commands to detect ollama.com model names and defer to the ollama runner initialization path

Documentation:

  • Add detailed README section covering ollama integration, installation steps, GPU support, management commands, and usage examples

Tests:

  • Add unit tests for the --ollama and GPU flags in install and reinstall runner commands
  • Add tests for the isOllamaModel utility function to validate model name detection

Support ollama runner commands with GPU variants

Add ollama model detection and runner initialization

Add comprehensive tests for ollama functionality

Add comprehensive documentation for ollama integration

Co-authored-by: ericcurtin <[email protected]>
Copilot AI review requested due to automatic review settings October 15, 2025 16:31
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 15, 2025

Reviewer's Guide

This PR integrates Ollama as an alternative model runner by introducing a global --ollama flag across all CLI commands, branching installation/start/stop logic to use Ollama-specific images, volumes, ports and container operations. It refactors the standalone package to generic, multi-runner container/volume/image helpers with new Ollama functions, extends GPU support to AMD ROCm, and complements these changes with thorough documentation and tests.

Sequence diagram for pulling an Ollama model

sequenceDiagram
    actor User
    participant CLI
    participant "Ollama Runner Manager"
    participant "Docker Engine"
    User->>CLI: docker model pull ollama.com/library/smollm:135m
    CLI->>"Ollama Runner Manager": isOllamaModel(model)
    "Ollama Runner Manager"->>"Docker Engine": ensureOllamaRunnerAvailable()
    "Docker Engine"-->>"Ollama Runner Manager": Ollama runner available
    CLI-->>User: Error: ollama model pull not yet implemented
    CLI-->>User: Suggest docker exec docker-ollama-runner ollama pull smollm:135m
Loading

Class diagram for runner type and resource helpers

classDiagram
    class RunnerOptions {
        +bool ollama
        +string gpuMode
        +bool doNotTrack
        +bool pullImage
        +bool pruneContainers
    }
    class CleanupOptions {
        +bool ollama
        +bool models
        +bool removeImages
    }
    class Standalone {
        +EnsureControllerImage()
        +EnsureOllamaImage()
        +EnsureModelStorageVolume()
        +EnsureOllamaStorageVolume()
        +PruneControllerContainers()
        +PruneOllamaControllerContainers()
        +PruneControllerImages()
        +PruneOllamaImages()
        +FindControllerContainer()
        +FindOllamaControllerContainer()
        +CreateControllerContainer()
        +CreateOllamaControllerContainer()
    }
    RunnerOptions <.. Standalone
    CleanupOptions <.. Standalone
Loading

File-Level Changes

Change Details Files
Integrate --ollama CLI option and branch runner logic
  • Add ollama field to runnerOptions and cleanupOptions structs
  • Branch default ports, image pulls, pruning and container create/find calls on opts.ollama
  • Update flags and help texts in install, start, stop, restart, reinstall, uninstall commands
  • Modify pull and run commands to detect Ollama models and initialize Ollama runner
cmd/cli/commands/install-runner.go
cmd/cli/commands/start-runner.go
cmd/cli/commands/stop-runner.go
cmd/cli/commands/restart-runner.go
cmd/cli/commands/reinstall-runner.go
cmd/cli/commands/uninstall-runner.go
cmd/cli/commands/pull.go
cmd/cli/commands/run.go
Add Ollama runner initialization and model detection utilities
  • Implement ensureOllamaRunnerAvailable for installation via controller containers
  • Add isOllamaModel helper to detect Ollama model names
cmd/cli/commands/install-runner.go
cmd/cli/commands/utils.go
Refactor standalone package for multi-runner support and add Ollama operations
  • Introduce labelRunnerType and runnerType constants
  • Implement createControllerContainerInternal, ensureImage, ensureStorageVolume helpers
  • Add Ollama-specific functions: Find, Create, EnsureImage, EnsureStorageVolume, Prune, PruneImages
cmd/cli/pkg/standalone/containers.go
cmd/cli/pkg/standalone/images.go
cmd/cli/pkg/standalone/volumes.go
cmd/cli/pkg/standalone/labels.go
cmd/cli/pkg/standalone/controller_image.go
cmd/cli/pkg/standalone/ports.go
Extend GPU support with AMD ROCm
  • Add GPUSupportROCm constant
  • Allow --gpu rocm in CLI parsing
  • Select ollama/ollama:rocm image variant when gpuVariant is rocm
cmd/cli/pkg/gpu/gpu.go
cmd/cli/commands/install-runner.go
cmd/cli/pkg/standalone/controller_image.go
Update README with comprehensive Ollama integration guide
  • Add Ollama Integration section with install, GPU, management, usage examples
  • Document port, volume and image differences between Ollama and Docker Model Runner
README.md
Add tests for Ollama CLI flags and model detection
  • Test presence and behavior of --ollama and --gpu rocm flags
  • Add unit tests for isOllamaModel detection logic
cmd/cli/commands/install-runner_test.go
cmd/cli/commands/reinstall-runner_test.go
cmd/cli/commands/utils_test.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ericcurtin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the Docker Model Runner CLI by introducing first-class support for Ollama. Users can now seamlessly install, configure, and manage Ollama as an alternative model runner, leveraging its model format and API. The changes include new command-line flags for runner management, intelligent GPU detection for both NVIDIA and AMD hardware, and preliminary integration for ollama.com model detection during pull and run operations. This integration aims to provide a unified experience for managing various AI model runtimes within the Docker ecosystem.

Highlights

  • Ollama Integration: Added comprehensive support for Ollama as an alternative model runner, allowing users to manage Ollama models directly through docker model commands.
  • GPU Support: Implemented GPU variant detection for Ollama, including explicit support for AMD ROCm GPUs via the --gpu rocm flag, alongside existing NVIDIA CUDA auto-detection.
  • Unified Command Interface: Extended existing install-runner, start-runner, stop-runner, restart-runner, reinstall-runner, and uninstall-runner commands with an --ollama flag to manage Ollama instances.
  • Model Detection: Introduced automatic detection for ollama.com models in pull and run commands, which will attempt to initialize the Ollama runner (though direct API integration for these commands is noted as future work).
  • Documentation: Updated the README.md with a detailed section on Ollama integration, covering installation, management, GPU support, and usage examples.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • There’s a lot of duplicated opts.ollama branching in runInstallOrStart and related commands—consider abstracting runner-specific logic behind a common interface or helper to reduce copy-pasted code.
  • The new ensureOllamaRunnerAvailable function mirrors much of the standalone initializer; consider merging them into a single ensureRunnerAvailable(ctx, runnerType) helper to avoid duplication and keep initialization consistent.
  • The TODO placeholders in pull.go and run.go currently error out instructing users to docker exec manually; improving UX by proxying pull/run commands to the ollama daemon directly would make the integration more seamless.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- There’s a lot of duplicated opts.ollama branching in runInstallOrStart and related commands—consider abstracting runner-specific logic behind a common interface or helper to reduce copy-pasted code.
- The new ensureOllamaRunnerAvailable function mirrors much of the standalone initializer; consider merging them into a single ensureRunnerAvailable(ctx, runnerType) helper to avoid duplication and keep initialization consistent.
- The TODO placeholders in pull.go and run.go currently error out instructing users to docker exec manually; improving UX by proxying pull/run commands to the ollama daemon directly would make the integration more seamless.

## Individual Comments

### Comment 1
<location> `cmd/cli/commands/install-runner_test.go:70` </location>
<code_context>
 	}
 }

+func TestInstallRunnerOllamaFlag(t *testing.T) {
+	cmd := newInstallRunner()
+
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding negative and edge case tests for the --ollama flag.

Please add tests for invalid flag values and cases where the flag is omitted or set to false, to improve coverage of flag parsing and error handling.
</issue_to_address>

### Comment 2
<location> `cmd/cli/commands/install-runner_test.go:105` </location>
<code_context>
+	}
+}
+
+func TestInstallRunnerGPUFlag(t *testing.T) {
+	cmd := newInstallRunner()
+
</code_context>

<issue_to_address>
**suggestion (testing):** Add tests for all supported GPU flag values and invalid input.

Please include test cases for 'auto', 'cuda', 'none', and an invalid value to fully cover the flag's behavior.
</issue_to_address>

### Comment 3
<location> `cmd/cli/commands/reinstall-runner_test.go:50-52` </location>
<code_context>
 	}
 }

+func TestReinstallRunnerOllamaFlag(t *testing.T) {
+	cmd := newReinstallRunner()
+
</code_context>

<issue_to_address>
**suggestion (testing):** Add negative and edge case tests for the --ollama flag in reinstall-runner.

Include tests for invalid flag values, explicit false, and absence of the flag to match the coverage in install-runner tests.

```suggestion
func TestReinstallRunnerOllamaFlag(t *testing.T) {
	cmd := newReinstallRunner()

	// Test absence of --ollama flag (should use default value)
	cmd.SetArgs([]string{})
	err := cmd.Execute()
	if err != nil {
		t.Errorf("Unexpected error when --ollama flag is absent: %v", err)
	}
	ollamaFlag := cmd.Flags().Lookup("ollama")
	if ollamaFlag == nil {
		t.Errorf("Expected flag '--ollama' not found")
	}
	// Check default value (assuming default is false, adjust if needed)
	if ollamaFlag.Value.String() != "false" {
		t.Errorf("Expected default value of --ollama to be 'false', got '%s'", ollamaFlag.Value.String())
	}

	// Test --ollama=true
	cmd = newReinstallRunner()
	cmd.SetArgs([]string{"--ollama=true"})
	err = cmd.Execute()
	if err != nil {
		t.Errorf("Unexpected error when --ollama=true: %v", err)
	}
	ollamaFlag = cmd.Flags().Lookup("ollama")
	if ollamaFlag.Value.String() != "true" {
		t.Errorf("Expected value of --ollama to be 'true', got '%s'", ollamaFlag.Value.String())
	}

	// Test --ollama=false
	cmd = newReinstallRunner()
	cmd.SetArgs([]string{"--ollama=false"})
	err = cmd.Execute()
	if err != nil {
		t.Errorf("Unexpected error when --ollama=false: %v", err)
	}
	ollamaFlag = cmd.Flags().Lookup("ollama")
	if ollamaFlag.Value.String() != "false" {
		t.Errorf("Expected value of --ollama to be 'false', got '%s'", ollamaFlag.Value.String())
	}

	// Test invalid value for --ollama
	cmd = newReinstallRunner()
	cmd.SetArgs([]string{"--ollama=notabool"})
	err = cmd.Execute()
	if err == nil {
		t.Errorf("Expected error when --ollama is set to an invalid value, got nil")
	}
}
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@ericcurtin ericcurtin marked this pull request as draft October 15, 2025 16:34
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds comprehensive support for using ollama as an alternative model runner, which is a great new feature. The changes include new CLI flags, GPU variant handling, and automatic management of containers and volumes for the ollama runner. The documentation and tests are thorough and well-written.

I've identified a critical issue with the auto-installation logic for the ollama runner that will prevent it from starting correctly. Additionally, there are a few areas with code duplication in the command implementations that could be refactored for better maintainability, and a couple of minor issues with user-facing error messages. My detailed feedback is in the comments below.

Comment on lines +135 to +137
if err := waitForStandaloneRunnerAfterInstall(ctx); err != nil {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The waitForStandaloneRunnerAfterInstall function is not suitable for waiting for the ollama runner. This function uses the global desktopClient, which is configured for the default model runner's port (e.g., 12434), not the ollama runner's port (11434). This will cause the installation to hang and eventually time out, preventing the ollama runner from being installed correctly.

A dedicated waiting logic that polls the ollama port is required.

(You will also need to add "net/http" to your imports for this suggestion to work).

Suggested change
if err := waitForStandaloneRunnerAfterInstall(ctx); err != nil {
return nil, err
}
if err := func() error {
url := fmt.Sprintf("http://127.0.0.1:%d", standalone.DefaultOllamaPort)
for tries := installWaitTries; tries > 0; tries-- {
resp, err := http.Get(url)
if err == nil {
resp.Body.Close()
if resp.StatusCode == http.StatusOK {
return nil
}
}
select {
case <-time.After(installWaitRetryInterval):
case <-ctx.Done():
return errors.New("cancelled waiting for ollama runner to initialize")
}
}
return errors.New("ollama runner took too long to initialize")
}(); err != nil {
return nil, err
}

Comment on lines 299 to 333
// If pruning containers (reinstall), remove any existing model runner containers.
if opts.pruneContainers {
if err := standalone.PruneControllerContainers(cmd.Context(), dockerClient, false, cmd); err != nil {
return fmt.Errorf("unable to remove model runner container(s): %w", err)
if opts.ollama {
if err := standalone.PruneOllamaControllerContainers(cmd.Context(), dockerClient, false, cmd); err != nil {
return fmt.Errorf("unable to remove ollama runner container(s): %w", err)
}
} else {
if err := standalone.PruneControllerContainers(cmd.Context(), dockerClient, false, cmd); err != nil {
return fmt.Errorf("unable to remove model runner container(s): %w", err)
}
}
} else {
// Check if an active model runner container already exists (install only).
if ctrID, ctrName, _, err := standalone.FindControllerContainer(cmd.Context(), dockerClient); err != nil {
var ctrID, ctrName string
var err error
if opts.ollama {
ctrID, ctrName, _, err = standalone.FindOllamaControllerContainer(cmd.Context(), dockerClient)
} else {
ctrID, ctrName, _, err = standalone.FindControllerContainer(cmd.Context(), dockerClient)
}
if err != nil {
return err
} else if ctrID != "" {
runnerType := "Model Runner"
if opts.ollama {
runnerType = "ollama runner"
}
if ctrName != "" {
cmd.Printf("Model Runner container %s (%s) is already running\n", ctrName, ctrID[:12])
cmd.Printf("%s container %s (%s) is already running\n", runnerType, ctrName, ctrID[:12])
} else {
cmd.Printf("Model Runner container %s is already running\n", ctrID[:12])
cmd.Printf("%s container %s is already running\n", runnerType, ctrID[:12])
}
return nil
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function contains a significant amount of duplicated logic within if opts.ollama blocks for handling different runner types. This reduces readability and maintainability.

You can refactor this by defining runner-specific configurations at the beginning of the function and then using a single, unified code path. The standalone package has already been refactored with generic functions like PruneControllerContainersByType and FindControllerContainerByType that you can leverage here.

This same pattern of duplication appears later in the function when ensuring images and volumes, and creating the container, which could also be refactored similarly.

runnerTypeStr := "Model Runner"
runnerTypeLabel := "model-runner"
pruneErrMsg := "unable to remove model runner container(s): %w"
if opts.ollama {
	runnerTypeStr = "ollama runner"
	runnerTypeLabel = "ollama"
	pruneErrMsg = "unable to remove ollama runner container(s): %w"
}

// If pruning containers (reinstall), remove any existing model runner containers.
if opts.pruneContainers {
	if err := standalone.PruneControllerContainersByType(cmd.Context(), dockerClient, false, cmd, runnerTypeLabel); err != nil {
		return fmt.Errorf(pruneErrMsg, err)
	}
} else {
	// Check if an active model runner container already exists (install only).
	ctrID, ctrName, _, err := standalone.FindControllerContainerByType(cmd.Context(), dockerClient, runnerTypeLabel)
	if err != nil {
		return err
	} else if ctrID != "" {
		if ctrName != "" {
			cmd.Printf("%s container %s (%s) is already running\n", runnerTypeStr, ctrName, ctrID[:12])
		} else {
			cmd.Printf("%s container %s is already running\n", runnerTypeStr, ctrID[:12])
		}
		return nil
	}
}

}
// TODO: Implement ollama-specific pull logic that communicates
// with the ollama daemon on port 11434
return fmt.Errorf("ollama model pull not yet implemented - please use 'docker exec docker-ollama-runner ollama pull %s'", model)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The suggested docker exec command in the error message is incorrect. It includes the ollama.com/ prefix in the model name, but the ollama CLI inside the container does not expect this prefix. This will cause confusion and the command will fail for the user.

The model name should have the ollama.com/ prefix stripped before being included in the error message.

(You will also need to add "strings" to your imports for this suggestion to work).

Suggested change
return fmt.Errorf("ollama model pull not yet implemented - please use 'docker exec docker-ollama-runner ollama pull %s'", model)
return fmt.Errorf("ollama model pull not yet implemented - please use 'docker exec docker-ollama-runner ollama pull %s'", strings.TrimPrefix(model, "ollama.com/"))

}
// TODO: Implement ollama-specific run logic that communicates
// with the ollama daemon on port 11434
return fmt.Errorf("ollama model run not yet implemented - please use 'docker exec -it docker-ollama-runner ollama run %s'", model)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the pull command, the suggested docker exec command in the error message is incorrect. It includes the ollama.com/ prefix, which the ollama run command inside the container does not expect. This will cause the suggested command to fail for the user.

The prefix should be stripped from the model name.

Suggested change
return fmt.Errorf("ollama model run not yet implemented - please use 'docker exec -it docker-ollama-runner ollama run %s'", model)
return fmt.Errorf("ollama model run not yet implemented - please use 'docker exec -it docker-ollama-runner ollama run %s'", strings.TrimPrefix(model, "ollama.com/"))

Comment on lines 41 to 63
// Remove any model runner containers.
if err := standalone.PruneControllerContainers(cmd.Context(), dockerClient, false, cmd); err != nil {
return fmt.Errorf("unable to remove model runner container(s): %w", err)
if opts.ollama {
if err := standalone.PruneOllamaControllerContainers(cmd.Context(), dockerClient, false, cmd); err != nil {
return fmt.Errorf("unable to remove ollama runner container(s): %w", err)
}
} else {
if err := standalone.PruneControllerContainers(cmd.Context(), dockerClient, false, cmd); err != nil {
return fmt.Errorf("unable to remove model runner container(s): %w", err)
}
}

// Remove model runner images, if requested.
if opts.removeImages {
if err := standalone.PruneControllerImages(cmd.Context(), dockerClient, cmd); err != nil {
return fmt.Errorf("unable to remove model runner image(s): %w", err)
if opts.ollama {
if err := standalone.PruneOllamaImages(cmd.Context(), dockerClient, cmd); err != nil {
return fmt.Errorf("unable to remove ollama image(s): %w", err)
}
} else {
if err := standalone.PruneControllerImages(cmd.Context(), dockerClient, cmd); err != nil {
return fmt.Errorf("unable to remove model runner image(s): %w", err)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function contains duplicated logic for handling ollama and default runners, which makes it verbose and harder to maintain. You can simplify this by abstracting the runner-specific calls into function variables, which will clean up the code and reduce duplication.

var pruneContainersFunc func(context.Context, client.ContainerAPIClient, bool, standalone.StatusPrinter) error
var pruneImagesFunc func(context.Context, client.ImageAPIClient, standalone.StatusPrinter) error
var pruneContainersErrMsg, pruneImagesErrMsg string

if opts.ollama {
	pruneContainersFunc = standalone.PruneOllamaControllerContainers
	pruneImagesFunc = standalone.PruneOllamaImages
	pruneContainersErrMsg = "unable to remove ollama runner container(s): %w"
	pruneImagesErrMsg = "unable to remove ollama image(s): %w"
} else {
	pruneContainersFunc = standalone.PruneControllerContainers
	pruneImagesFunc = standalone.PruneControllerImages
	pruneContainersErrMsg = "unable to remove model runner container(s): %w"
	pruneImagesErrMsg = "unable to remove model runner image(s): %w"
}

// Remove any model runner containers.
if err := pruneContainersFunc(cmd.Context(), dockerClient, false, cmd); err != nil {
	return fmt.Errorf(pruneContainersErrMsg, err)
}

// Remove model runner images, if requested.
if opts.removeImages {
	if err := pruneImagesFunc(cmd.Context(), dockerClient, cmd); err != nil {
		return fmt.Errorf(pruneImagesErrMsg, err)
	}
}

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Add initial ollama runner support alongside the existing model-runner, including container/image/volume management, CLI flags, and basic model detection.

  • Introduces runner typing via labels to distinguish model-runner vs ollama resources.
  • Adds CLI flags and helper paths to install/start/stop/reinstall/uninstall the ollama runner, with tests and docs.
  • Implements image/volume/container helpers for ollama, plus basic ollama model detection.

Reviewed Changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
cmd/cli/pkg/standalone/volumes.go Generalizes volume ensure logic and adds an ollama storage volume.
cmd/cli/pkg/standalone/ports.go Adds default ollama port 11434.
cmd/cli/pkg/standalone/labels.go Adds label and constants to differentiate runner types.
cmd/cli/pkg/standalone/images.go Refactors image pull logic and adds prune/pull for ollama images.
cmd/cli/pkg/standalone/controller_image.go Adds ollama image name/version/variant helpers.
cmd/cli/pkg/standalone/containers.go Adds ollama container helpers and runner-type-aware find/prune/create.
cmd/cli/pkg/gpu/gpu.go Adds GPUSupportROCm enum.
cmd/cli/commands/utils_test.go Tests ollama model detection helper.
cmd/cli/commands/utils.go Adds isOllamaModel helper.
cmd/cli/commands/uninstall-runner.go Adds --ollama support and image pruning path.
cmd/cli/commands/stop-runner.go Adds --ollama flag.
cmd/cli/commands/start-runner.go Adds --ollama flag and GPU help updates.
cmd/cli/commands/run.go Routes ollama models to the ollama runner path (not yet implemented).
cmd/cli/commands/restart-runner.go Adds --ollama flag and help updates.
cmd/cli/commands/reinstall-runner_test.go Tests for --ollama flag presence/behavior.
cmd/cli/commands/reinstall-runner.go Adds --ollama flag and help updates.
cmd/cli/commands/pull.go Routes ollama models to the ollama runner path (placeholder error for now).
cmd/cli/commands/list.go Adds TODO for listing ollama models.
cmd/cli/commands/install-runner_test.go Adds tests for --ollama and GPU=rocm flags.
cmd/cli/commands/install-runner.go Implements ensureOllamaRunnerAvailable and integrates --ollama throughout.
README.md Documents ollama integration, usage, and GPU guidance.

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

// Note: CUDA GPUs use the base "latest" image
if detectedGPU == gpupkg.GPUSupportCUDA {
return "" // ollama/ollama:latest works for CUDA
}
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ollamaImageVariant never returns 'rocm' for AMD GPUs, so the ROCm image is not selected in auto paths (e.g., ensureOllamaRunnerAvailable). Return 'rocm' when detectedGPU == GPUSupportROCm to select the correct image variant.

Suggested change
}
}
if detectedGPU == gpupkg.GPUSupportROCm {
return "rocm"
}

Copilot uses AI. Check for mistakes.
Comment on lines +133 to +136
// Poll until we get a response from the ollama runner.
// Note: We reuse the same wait logic, assuming ollama responds similarly
if err := waitForStandaloneRunnerAfterInstall(ctx); err != nil {
return nil, err
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waitForStandaloneRunnerAfterInstall checks the Desktop model-runner status, not the ollama container, so ollama readiness will likely time out even when the daemon is up. Implement a dedicated readiness check (e.g., try HTTP to http://127.0.0.1:11434/api/tags or poll the container state) and use it here instead.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +19
// GPUSupportROCm indicates ROCm GPU support (AMD).
GPUSupportROCm
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GPUSupportROCm is defined but ProbeGPUSupport never returns it, so 'auto' detection will not select ROCm. Extend ProbeGPUSupport to detect ROCm (e.g., presence of /dev/kfd and/or rocm-smi) and return GPUSupportROCm when applicable.

Copilot uses AI. Check for mistakes.
printer.Printf("Creating model storage volume %s...\n", modelStorageVolumeName)
volume, err := dockerClient.VolumeCreate(ctx, volume.CreateOptions{
Name: modelStorageVolumeName,
printer.Printf("Creating model storage volume %s...\n", volumeName)
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This message is used for both model-runner and ollama volumes; it can be confusing when creating the ollama volume. Consider a generic message like 'Creating storage volume %s...' or include the runner type in the message.

Suggested change
printer.Printf("Creating model storage volume %s...\n", volumeName)
printer.Printf("Creating %s storage volume %s...\n", runnerType, volumeName)

Copilot uses AI. Check for mistakes.
// Start the container.
printer.Printf("Starting model runner container %s...\n", controllerContainerName)
if err := ensureContainerStarted(ctx, dockerClient, controllerContainerName); err != nil {
printer.Printf("Starting model runner container %s...\n", containerName)
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The start message always says 'model runner' even for ollama containers. Since createControllerContainerInternal receives runnerType, prefer printer.Printf(\"Starting %s container %s...\\n\", runnerType, containerName) to reflect the correct runner.

Suggested change
printer.Printf("Starting model runner container %s...\n", containerName)
printer.Printf("Starting %s container %s...\n", runnerType, containerName)

Copilot uses AI. Check for mistakes.
_ = dockerClient.ContainerRemove(ctx, resp.ID, container.RemoveOptions{Force: true})
}
return fmt.Errorf("failed to start container %s: %w", controllerContainerName, err)
return fmt.Errorf("failed to start container %s: %w", containerName, err)
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The start message always says 'model runner' even for ollama containers. Since createControllerContainerInternal receives runnerType, prefer printer.Printf(\"Starting %s container %s...\\n\", runnerType, containerName) to reflect the correct runner.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants