mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Ajouter un serveur MCP demandait d'écrire soi-même `npx -y @scope/paquet …` dans la modale, en devinant le nom du paquet. Le catalogue liste une vingtaine de serveurs connus, commande déjà renseignée, classés par catégorie. - internal/loki/mcp_catalog.json est EMBARQUÉ dans le binaire (go:embed), pas interrogé sur le réseau : Loki tourne hors ligne, et rien de ce qui s'exécute sur la machine ne vient d'un annuaire distant. Pour proposer un serveur de plus : éditer le fichier et recompiler. - Choisir une entrée n'installe rien. Ça préremplit la modale d'ajout existante et l'utilisateur relit la commande avant d'enregistrer — un serveur stdio exécute un process arbitraire, au même titre que l'outil bash du mode agent. Aucune ligne de mcp_client.go n'est touchée : le catalogue s'arrête à l'affichage, tout le reste passe par l'API MCP déjà en place. - Une entrée dont le runtime manque (npx ou uvx absent) le signale dans la liste, plutôt que de laisser l'utilisateur découvrir l'échec au démarrage du serveur. - Les entrées qui réclament une clé d'API la rappellent avant l'enregistrement, au lieu d'enregistrer un serveur qui ne peut pas se connecter. - Les entrées Python publiées avant le SDK MCP 2.0 sont épinglées avec `uvx --with "mcp<2"` : sans cela elles plantent sur ImportError: McpError. - Le Dockerfile gagne uv/uvx (~35 Mo). Sans lui, 9 des 21 entrées s'affichent sans pouvoir démarrer dans le conteneur. Intensité du raisonnement (REASONING_EFFORT) L'interrupteur Raisonnement était binaire. llama-server accepte `reasoning_effort` dans /v1/chat/completions : `none` coupe le raisonnement, toute autre valeur est passée au gabarit jinja du modèle. - Nouvelle clé de preset REASONING_EFFORT — donc réglée par modèle, comme le reste du preset. Vide = on n'envoie rien et le gabarit garde son comportement. - Pas de repli à prévoir : un gabarit qui ne lit pas la valeur l'ignore sans erreur. En pratique seuls gpt-oss et apparentés changent de comportement, et le sous-titre du réglage le dit — promettre un effet universel serait faux. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
97 lines
4.7 KiB
Docker
97 lines
4.7 KiB
Docker
# ── Loki — image GPU (fork d'AJEAN, https://github.com/nathaninline/ajean)
|
|
#
|
|
# Deux étapes seulement :
|
|
# 1. compilation du binaire Go `loki` (UI embarquée via go:embed) ;
|
|
# 2. runtime = l'image serveur CUDA OFFICIELLE de llama.cpp — llama-server
|
|
# y est précompilé et maintenu par l'équipe amont (base nvidia/cuda
|
|
# runtime, backends .so dans /app, architectures GPU courantes).
|
|
# Aucune compilation CUDA ici : le build complet prend quelques minutes.
|
|
#
|
|
# Épingler une version : --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server-cuda-b10423
|
|
# Variante CPU (test sans GPU) : --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server
|
|
# Pré-requis d'exécution GPU : NVIDIA Container Toolkit sur l'hôte.
|
|
|
|
# Déclaré avant le premier FROM : requis pour être utilisable dans un FROM.
|
|
ARG LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server-cuda
|
|
|
|
# ── Étape 1 : binaire Go loki ───────────────────────────────────────────
|
|
FROM golang:1.25 AS gobuild
|
|
WORKDIR /src
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
COPY cmd/ cmd/
|
|
COPY internal/ internal/
|
|
COPY tools/ tools/
|
|
RUN CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o /out/loki ./cmd/loki
|
|
|
|
# ── Étape 2 : runtime sur l'image serveur CUDA officielle ───────────────
|
|
FROM ${LLAMACPP_IMAGE} AS runtime
|
|
|
|
# Marqueur de build (sha court), injecté par le workflow GitHub.
|
|
ARG LOKI_VERSION=dev
|
|
LABEL org.opencontainers.image.revision="${LOKI_VERSION}" \
|
|
org.opencontainers.image.source="https://github.com/R0m1k3/Loki" \
|
|
org.opencontainers.image.description="Loki — fork conteneurisé d'AJEAN (github.com/nathaninline/ajean, MIT)"
|
|
|
|
# git pour les outils de l'agent ; nodejs/npm pour les serveurs MCP lancés
|
|
# via npx ; tini en PID 1. curl et libgomp1 sont déjà dans l'image amont.
|
|
# Node 22 depuis NodeSource et non depuis Ubuntu (qui livre Node 18) : Playwright
|
|
# et la plupart des serveurs MCP réclament Node ≥ 20.
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
git tini ca-certificates curl gnupg \
|
|
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
|
&& apt-get install -y --no-install-recommends nodejs \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# uv/uvx : lanceur des serveurs MCP écrits en Python (mcp-server-git, -fetch,
|
|
# -time, sqlite, docker…). Sans lui, une bonne partie du catalogue embarqué
|
|
# s'affiche mais ne peut pas démarrer. Deux binaires statiques, ~35 Mo.
|
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
|
|
|
|
# Playwright + Chromium : l'outil web_screenshot capture une page RENDUE
|
|
# (JavaScript exécuté), ce que le moteur web intégré ne sait pas faire.
|
|
# Coût assumé : ~500 Mo à 1 Go d'image. Mettre PLAYWRIGHT=0 pour bâtir une image
|
|
# légère — l'outil se désactive alors tout seul (le binaire absent est détecté).
|
|
ARG PLAYWRIGHT=1
|
|
ARG PLAYWRIGHT_VERSION=latest
|
|
ENV PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers
|
|
# Les polices sont INDISPENSABLES : sans elles, Chromium rend les pages sans
|
|
# AUCUN texte — boutons et titres sortent vides, seuls les images et les aplats
|
|
# apparaissent. Noto couvre l'essentiel des écritures, Liberation fournit les
|
|
# substituts d'Arial/Times que réclament la plupart des sites.
|
|
RUN if [ "$PLAYWRIGHT" = "1" ]; then \
|
|
npm i -g playwright@${PLAYWRIGHT_VERSION} \
|
|
&& playwright install --with-deps chromium \
|
|
&& apt-get update \
|
|
&& apt-get install -y --no-install-recommends \
|
|
fonts-liberation fonts-dejavu-core fonts-noto-core \
|
|
fonts-noto-cjk fonts-noto-color-emoji \
|
|
&& fc-cache -f \
|
|
&& rm -rf /root/.npm /var/lib/apt/lists/* ; \
|
|
fi
|
|
|
|
COPY --from=gobuild /out/loki /usr/local/bin/loki
|
|
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh && mkdir -p /data /models
|
|
|
|
# llama-server et ses .so vivent dans /app (convention de l'image amont).
|
|
ENV LOKI_CONTAINER=1 \
|
|
LOKI_HOME=/data \
|
|
LOKI_MODEL_DIRS=/models \
|
|
LOKI_ENGINE_BIN=/app/llama-server \
|
|
LD_LIBRARY_PATH=/app \
|
|
NVIDIA_VISIBLE_DEVICES=all \
|
|
NVIDIA_DRIVER_CAPABILITIES=compute,utility
|
|
|
|
# 8090 : interface web (seule à exposer). Le moteur (8080) reste interne au
|
|
# conteneur — il n'est pas authentifié par défaut.
|
|
EXPOSE 8090
|
|
|
|
# Remplace le HEALTHCHECK de l'image amont (qui vise le moteur sur :8080).
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
|
CMD curl -fsS "http://localhost:${LOKI_WEB_PORT:-8090}/" >/dev/null || exit 1
|
|
|
|
WORKDIR /data
|
|
# Remplace l'ENTRYPOINT de l'image amont (/app/llama-server).
|
|
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
|