Sceller / ouvrir un blob par le Go (mémoire verrouillée : erreur dédiée,
rien d'écrit en clair) et faire exécuter un appel d'outil par sa boucle
— les deux ponts dont la conversation Rust aura besoin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
L'en-tête de l'interface interroge /api/status en boucle : il est
désormais assemblé par la façade, à partir des aides portées (état du
service par le fichier PID, sonde /health, preset externe, cause d'un
échec de chargement lue dans le journal, pourcentage de chargement, preset
actif, alertes de volume et de FUSE). Sur une base réelle, sa réponse est
octet pour octet celle du Go.
Journal du moteur, emplacements et nombre de couches du modèle suivent.
L'état du moteur s'appuie sur la résolution des modèles de gguf.rs plutôt
que sur sa propre copie.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RAM lue dans /proc/meminfo, jauges des cartes par un seul nvidia-smi
partagé entre tous les onglets (cache de deux secondes, une minute quand
nvidia-smi est absent), comme le Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le module sysinfo de loki-rs reprend, à l'identique, ce dont les routes
/api/ram, /api/vram et le bandeau de /api/status ont besoin côté Go.
La RAM se lit dans /proc/meminfo (MemTotal moins MemAvailable, en Mo) ;
hors Linux la façade rend (0, 0) et l'interface masque le bloc. Les jauges
GPU interrogent nvidia-smi, bornées à dix secondes, et passent par un cache
partagé : deux secondes de validité, une minute quand le binaire est
introuvable, et un verrou tenu pendant la requête pour que les onglets
simultanés attendent la même lecture au lieu d'en lancer chacun une. La
structure GpuStat sérialise name, used, total, util et temp, les noms que
handleVram envoie déjà.
L'alerte « /data n'est PAS un volume monté » et le conseil fuse.shfs
d'Unraid gardent leurs textes, leur règle du montage le plus long et leur
cache d'une minute. Les dossiers de modèles venant de la base, le conseil
reçoit leur lecture en fermeture asynchrone, appelée seulement quand le
cache expire.
Les tests Go de sys_storagefuse_test.go et la partie cache de
web_vram_test.go sont portés un pour un ; le test hors conteneur, qui
touche à l'environnement, vit seul dans tests/sysinfo.rs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La surface compatible OpenAI ne fait plus le détour par le Go : la façade
authentifie avec la clé des complétions (préflight CORS exempté), réécrit
le corps vers le second slot quand il est en service (id_slot à 1, valeurs
gardées telles quelles), retire les X-Forwarded-* et relaie au moteur sans
tampon — Host d'origine, sauf pour Strata.
Les décisions restent au Go, qui tient l'état de la conversation : la
façade lui demande où router, ouvre un ticket « en vol » avant de relayer
(refus pendant un benchmark ou une optimisation, avec Retry-After) et le
rend quand le flux se termine, que le client parte ou que le moteur soit
injoignable. Sans ticket obtenu, la requête est refusée : le Go pourrait
sinon effacer le slot en plein calcul.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deux routes de pilotage de plus en Rust, lues dans la base à travers le
Go. La configuration sort clés triées, comme json.Encoder le fait d'une
map Go. Faux serveur Go de test à store en mémoire, réutilisable par les
lots suivants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le Go expose sa base à la façade par l'API interne : lecture, écriture,
suppression d'une clé et lecture d'un bucket entier. Il reste l'unique
propriétaire du fichier bbolt ; les écritures passent par putBytes/update
et invalident son cache comme une écriture locale. Base illisible : 503,
pour que Rust distingue « rien » de « pas pu lire ».
Côté Rust : client du store (seul point de passage, que la migration
finale de la base ne touchera qu'ici), routeur /api avec contexte partagé
et garde d'authentification réutilisable ; /api/ping y emménage. Modules
réservés aux aides portées ensuite (système, état du moteur, presets,
chemins, GGUF).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
En conteneur, start/stop/restart/status du moteur passent par
`loki-rs engine <action>`, port à l'identique de la supervision Go :
`loki serve` lancé chef de session, fichier PID et journal aux mêmes
chemins (serviceIsActive, l'UI et `loki logs` lisent les mêmes fichiers),
contrôle à 2 s avec la fin du journal en cas d'échec, arrêt de tout
l'arbre — session, groupe et filiation, pour le moteur de Strata qui prend
sa propre session — avec les mêmes délais (SIGTERM, 4 s, SIGKILL, 20 s).
Le Go garde ses garde-fous (optimisation en cours, preset externe) puis
délègue au loki-rs voisin de son binaire ; la dernière ligne d'erreur du
superviseur devient l'erreur montrée par l'UI. LOKI_ENGINE_SUPERVISOR=go
revient à l'ancienne supervision. `loki serve`, qui construit la ligne de
commande du moteur, ne change pas : il aura son propre lot.
Le contrôle « démarré ? » regarde si l'enfant est sorti plutôt que le
signal 0 : un enfant mort reste un zombie tant que son parent vit, et un
zombie répond encore au signal 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
L'interface (index, marked, service worker, manifeste, polices) est
désormais servie par loki-rs, embarquée par build.rs depuis la même source
que le go:embed — les deux binaires d'un build servent la même UI. Mêmes
en-têtes de cache que le Go, gzip à la première demande puis gardé en
mémoire, jamais sur les polices ni en HEAD.
L'authentification de pilotage est portée à l'identique (requireWebAuth,
crossSiteReject, localHostName, Bearer en temps constant, mêmes messages,
mêmes codes) ; les cas de TestCrossSiteReject sont repris un pour un. La
clé est demandée à l'API interne du Go à chaque requête ; si elle ne
répond pas proprement, la façade ferme (503). /api/ping est la première
route authentifiée servie par Rust.
Le jeton de l'API interne est tiré au hasard à chaque démarrage et passé
au Go par l'environnement. La façade rend 404 sur /internal/* venu de
l'extérieur et efface X-Loki-Internal entrant avant tout relais.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Premier lot de la migration vers Rust. Le binaire loki-rs :
- serve : prend le port public (8090), lance `loki web 8091` en écoute
locale et lui relaie tout — HTTP, flux SSE trame par trame, WebSocket.
Les en-têtes de bout en bout passent intacts (Host, Authorization,
Origin, Sec-Fetch-*, X-Forwarded-Proto : le Go en tire ses contrôles
d'accès) ; X-Loki-Via entrant est effacé, un client ne doit jamais
pouvoir se faire passer pour le tunnel. Go mort : relancé avec attente
croissante, 502 lisible entre-temps.
- self-update : lit la release « rolling », installe loki et loki-rs dans
$LOKI_HOME/bin/<build>/ après vérification SHA-256, bascule par
réécriture atomique de release.json. Les versions s'ordonnent par numéro
de run CI ; une ABI d'image différente n'est jamais installée. Toute
erreur laisse l'état précédent, le démarrage n'est jamais bloqué.
Le HTTPS passe par curl (présent dans l'image) : pas de pile TLS ici.
- which-bin : dossier d'où l'entrypoint prend les deux binaires, toujours
ensemble.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>