From 7def2990cea8b675357c424a3dae87facd6f0737 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Mon, 24 Aug 2026 20:22:22 +1000 Subject: [PATCH] feat: support physical and Docker Ollama runtimes --- README.md | 25 +++++++++++++++++++++++++ dashboard/manifest.json | 2 +- dashboard/plugin_api.py | 30 ++++++++++++++++++++++++++++-- plugin.yaml | 4 ++-- scripts/install_ollama.sh | 39 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 74b2582..af80fdb 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,31 @@ https://gitea.beyondcloud.solutions/dennii/Hermes-Ollama_Models.git In Hermes Dashboard, open **Plugins**, choose **Install from repository**, enter the URL above, and install. The repository contains the root `plugin.yaml`, dashboard manifest, backend API, compiled frontend bundle, stylesheet, and an opt-in prerequisite declaration. On Linux, the Hermes installer will verify Ollama, install it with the official Ollama installer when missing, and install the plugin's `pypdf` dependency before committing the plugin into `~/.hermes/plugins/`. Ollama installation requires the Hermes container to run as root, which is the expected configuration for a privileged ZimaOS deployment. If the container is not running as root, the plugin install stops without enabling a partially configured plugin. After installation or an update, restart only the Hermes dashboard service if requested by the installer. +## Physical and Docker deployments + +The plugin supports both deployment types: + +- **Physical/Linux Hermes:** Ollama defaults to `http://localhost:11434`. If Ollama is missing, the prerequisite installer can install it on a root-run host. +- **Docker Hermes:** Ollama should normally run as a separate service or on the Docker host. The plugin does not install Ollama inside the Hermes container. Set `OLLAMA_HOST` to the reachable Ollama base URL, without `/v1`, for example `http://ollama:11434` for a Compose service or `http://host.docker.internal:11434` for a host service. + +For host access on Linux Docker, add this to the Hermes service when needed: + +```yaml +extra_hosts: + - "host.docker.internal:host-gateway" +environment: + OLLAMA_HOST: http://host.docker.internal:11434 +``` + +For Compose service-to-service networking, use the Ollama service name instead: + +```yaml +environment: + OLLAMA_HOST: http://ollama:11434 +``` + +The dashboard plugin API is mounted when the dashboard starts. Restart Hermes after installing or enabling the plugin; otherwise the plugin page can load while `/api/plugins/ollama-manager/status` still returns 404. + ## Security limits - Uploaded files are limited to 20 MiB each diff --git a/dashboard/manifest.json b/dashboard/manifest.json index d463a07..d6396f5 100644 --- a/dashboard/manifest.json +++ b/dashboard/manifest.json @@ -3,7 +3,7 @@ "label": "Ollama Models", "description": "Inspect, manage, and chat with local Ollama models, including shared persistent conversations, performance metrics, images, PDFs, URLs, and live memory telemetry.", "icon": "Cpu", - "version": "1.5.2", + "version": "1.5.3", "tab": {"path": "/ollama-manager", "position": "after:models"}, "entry": "dist/index.js", "css": "dist/style.css", diff --git a/dashboard/plugin_api.py b/dashboard/plugin_api.py index d514e93..d45318a 100644 --- a/dashboard/plugin_api.py +++ b/dashboard/plugin_api.py @@ -31,7 +31,20 @@ from pydantic import BaseModel, Field from hermes_constants import get_hermes_home router = APIRouter() -LOCAL_OLLAMA = os.environ.get("OLLAMA_HOST", "http://localhost:11434").rstrip("/") + + +def _running_in_container() -> bool: + return Path("/.dockerenv").exists() or Path("/run/.containerenv").exists() + + +def _ollama_base_url() -> str: + configured = os.environ.get("OLLAMA_HOST", "").strip() + if configured: + return configured.rstrip("/") + return "http://ollama:11434" if _running_in_container() else "http://localhost:11434" + + +LOCAL_OLLAMA = _ollama_base_url() REMOTE_OLLAMA = "https://ollama.com" CATALOG_FILE = "catalog.json" MODEL_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:/-]{0,190}$") @@ -1396,8 +1409,21 @@ def status() -> dict[str, Any]: variants.append(variant) row["variants"] = sorted(variants, key=lambda item: (item.get("size_bytes") or 0, item["name"])) + ollama_version = _ollama_version() return { - "ollama": {"available": bool(tags or ps_rows), "version": _ollama_version(), "endpoint": LOCAL_OLLAMA}, + "ollama": { + "available": bool(tags or ps_rows or ollama_version), + "version": ollama_version, + "endpoint": LOCAL_OLLAMA, + "containerized": _running_in_container(), + "configured_endpoint": bool(os.environ.get("OLLAMA_HOST", "").strip()), + "connection_hint": ( + "Set OLLAMA_HOST to a reachable Ollama service, such as " + "http://ollama:11434 or http://host.docker.internal:11434." + if _running_in_container() and not (tags or ps_rows or ollama_version) + else "" + ), + }, "models": local, "popular": popular, "popular_filter": { diff --git a/plugin.yaml b/plugin.yaml index cb9f8a9..62c449a 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,10 +1,10 @@ name: ollama-manager -version: 1.5.2 +version: 1.5.3 description: Native dashboard manager and chat interface for local Ollama models, attachments, URLs, shared persistent conversations, performance metrics, and live runtime telemetry. auto_install_dependencies: true python_dependencies: - "pypdf>=6.0,<7.0" external_dependencies: - name: Ollama - check: ollama --version + check: bash scripts/install_ollama.sh --check install: bash scripts/install_ollama.sh diff --git a/scripts/install_ollama.sh b/scripts/install_ollama.sh index 6e2a7ca..e01f35d 100755 --- a/scripts/install_ollama.sh +++ b/scripts/install_ollama.sh @@ -7,6 +7,45 @@ if [[ "$(uname -s)" != "Linux" ]]; then exit 1 fi +is_container() { + if [[ -f /.dockerenv ]]; then + return 0 + fi + [[ -f /run/.containerenv ]] +} + +ollama_endpoint() { + if [[ -n "${OLLAMA_HOST:-}" ]]; then + printf '%s' "${OLLAMA_HOST%/}" + elif is_container; then + printf '%s' 'http://ollama:11434' + else + printf '%s' 'http://localhost:11434' + fi +} + +check_endpoint() { + command -v curl >/dev/null 2>&1 || return 1 + curl --fail --silent --show-error --max-time 5 "$(ollama_endpoint)/api/version" >/dev/null +} + +if [[ "${1:-}" == "--check" ]]; then + if command -v ollama >/dev/null 2>&1 && ! is_container; then + ollama --version >/dev/null + exit 0 + fi + check_endpoint + exit $? +fi + +if is_container; then + if check_endpoint; then + exit 0 + fi + printf '%s\n' 'Docker/container runtime detected. Configure OLLAMA_HOST to a reachable Ollama service (for example http://ollama:11434 or http://host.docker.internal:11434); Hermes will not install Ollama inside its own container.' >&2 + exit 1 +fi + if command -v ollama >/dev/null 2>&1; then ollama --version >/dev/null exit 0