L'amont ne connaît qu'un fil unique (bkChat/conversation) que « clear chat »
effaçait définitivement. On garde toute la machinerie (un seul conv en
mémoire, mêmes flux SSE, même compactage) mais rangée par discussion :
bkChat/index liste des discussions (métadonnées seules)
bkChat/active discussion ouverte, partagée par tous les appareils
bkChat/conv:<id> état complet d'une discussion
Basculer réutilise le mécanisme d'epoch du reset : les abonnés SSE reçoivent
{reset:true} et rejouent le nouveau fil — aucun code de rendu à toucher. Le
fil unique existant est repris comme première discussion au premier
démarrage, et sa clé d'origine est laissée intacte.
- routes /api/conversations (liste, new, switch, rename, delete)
- barre latérale : liste (titre déduit du 1er message, date, nb d'échanges),
bouton +, renommer, supprimer ; lignes construites en DOM et non en
innerHTML, les titres venant de messages utilisateur
- suppression de la dernière discussion : convCreate et non convNew, qui
aurait réenregistré celle qu'on vient d'effacer
Le bouton « Vérifier les mises à jour » répondait « GitHub a répondu 404 » :
il interrogeait les releases du dépôt du fork, qui n'en publie aucune. En
conteneur, remplacer le binaire n'a de toute façon pas de sens — l'UI, l'API
et la CLI renvoient désormais « docker compose pull ».
Vérifié en conteneur : création, bascule, renommage (titre accentué avec
< > &), suppression de l'active puis de la dernière ; /api/update et
loki update renvoient la note Docker.
Le sélecteur de l'éditeur de modèle proposait encore « Précompilé » et
« Compilé » — deux installations que Loki ne fait pas en conteneur : cliquer
répondait « installez d'abord llama.cpp… ». Pire, le moteur de l'image ne
correspondant à aucun des deux, il était classé « Personnalisé ».
En conteneur, ces deux options laissent place à « Image » (sélectionnée par
défaut, y compris pour un preset sans BIN) ; « Personnalisé » reste pour un
binaire déposé dans /data/backends.
Le moteur de l'image est désormais déclaré par l'image elle-même via
LOKI_ENGINE_BIN (Dockerfile + entrypoint) au lieu d'être deviné d'après le
chemin : /api/llamacpp expose provided et provided_bin.
Attribution : sous le nom Loki, « fork de AJEAN » avec lien vers le dépôt
d'origine.
Vérifié dans l'image : provided=true, provided_bin=/app/llama-server,
BIN semé identique ; build, vet et tests verts.
Le panneau « Moteur » proposait d'installer llama.cpp alors que l'image le
fournit déjà (/app/llama-server) : cliquer lançait une compilation qui
échouait sur « outils manquants : cmake », l'image n'embarquant ni cmake ni
compilateur.
- engineProvided() : vrai en conteneur quand BIN désigne un exécutable
existant HORS de LOKI_HOME (donc ni dépôt cloné, ni précompilé, ni backend
custom, qui sont gérés par Loki) ; exposé en clé 'provided' de /api/llamacpp
- les routes install / install-custom / update refusent en 409 avec un
message explicite au lieu de partir en build
- l'UI affiche l'état réel (chemin du binaire) et masque les trois modes
Le journal du moteur n'était repliable que par un second clic sur la pastille
d'état — sans chevron ni titre cliquable, contrairement à toutes les autres
sections de la barre latérale. Il devient un <details><summary> comme les
autres ; la pastille reste un raccourci et le chargement suit l'événement
toggle, quel que soit le moyen d'ouverture.
Vérifié dans l'image : provided=true, config_bin=/app/llama-server,
POST /api/llamacpp/install → 409 explicite, <details id="svc-log-box"> servi.
- NOTICE.md : Loki est un fork d'AJEAN (nathaninline, MIT), liste des
modifications ; LICENSE amont conservée à l'identique.
- README réécrit : bandeau fork, architecture conteneur, démarrage Docker,
procédure Unraid (plugin Nvidia Driver), différences avec l'amont.
- UI : le logo pixel-art épelle désormais LOKI (il épelait encore AJEAN),
infobulle d'attribution sur la marque ; index.html régénéré.
- Workflow GHCR : libération d'espace disque du runner (l'étape CUDA devel
ne tient pas dans les ~14 Go libres), build-args CUDA_ARCHS/LOKI_VERSION,
cache GHA en mode min (plafond 10 Go).
- Dockerfile 3 étapes : llama.cpp CUDA (flags de backend_build.go, sauf
GGML_NATIVE=OFF — l'image est bâtie sur un runner, pas sur la machine
cible), binaire Go statique, runtime CUDA léger (tini, git, nodejs pour
les serveurs MCP npx).
- docker-entrypoint.sh : sème BIN/HOST/PORT (+ MODEL/CTX/NGL depuis l'env,
au premier boot seulement), lance le moteur en supervision PID puis
'loki web' au premier plan. UI seule exposée (8090) ; le moteur (8080,
non authentifié) reste interne.
- Nouvelle commande 'loki config [get|set]' : configuration non interactive
(la config vit dans bbolt, pas dans un fichier plat).
- docker-compose.yml (build local, réservation GPU) + variante Unraid
(image GHCR, runtime nvidia) ; volumes /data (LOKI_HOME) et /models.
Un seul conteneur car llm_client.go joint le moteur sur localhost (hérité
de l'amont).
Nouveau sys_service_container.go : supervision par fichier PID portée du mode
utilisateur macOS (Setsid, SIGTERM sur le groupe puis SIGKILL, log fichier).
sys_service_linux.go bascule automatiquement quand /run/systemd/system est
absent ou que LOKI_CONTAINER=1 ; une install systemd classique est inchangée.
Le tunnel ajean.link suit la même logique (uiServiceCtl / uiServiceActive).
Sans ce repli, changer de modèle depuis l'UI (serviceAction restart)
échouait sur un systemctl absent — le conteneur était inutilisable.
Testé sans systemd : start / status / restart / stop, PID suivi,
processus enfant arrêté avec le groupe. build linux+darwin+windows OK,
go vet + go test verts.
- module github.com/R0m1k3/Loki, cmd/loki, internal/loki (package loki)
- LOKI_HOME, LOKI_MODEL_DIRS, LOKI_SERVICE, LOKI_DL_CONNS ; /etc/loki ;
units loki-engine / loki-ui ; binaire et aide CLI
- updateRepo pointe sur R0m1k3/Loki (l'auto-update ne tirera plus les
binaires AJEAN amont)
Conservé à l'identique : le domaine ajean.link (service de tunnel amont),
les littéraux de migration 0.7.x (migrate_07.go), RELEASE_NOTES.md et
LICENSE (historique et licence de l'amont).
go build/vet/test : verts.