mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
78d15cefbfdb1ec11540ca93f81c0cd42ae8b9d2
629
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
78d15cefbf |
MoE : corrections de relecture du lot 2 — LOAD_GUARD ne refuse plus sur une borne fausse, et le refus se voit
La garde du mode de chargement est le seul refus actif par défaut du lot 2 : il ne doit tomber que sur un échec certain, et se dire là où l'on regarde. - Serveurs --rpc (ou LLAMA_ARG_RPC) : une part des poids part ailleurs, la VRAM locale ne borne plus rien — avertissement, jamais de refus. - Mac Intel : la mémoire n'est unifiée que sur Apple Silicon ; ailleurs la VRAM est inconnue, donc jamais de refus (l'agrandissement du cache RAM reste coupé sur tout macOS, comme avant). - LLAMA_ARG_NO_MMAP / LLAMA_ARG_MLOCK restées dans l'environnement ne comptent plus sur un moteur à --load-mode, qui les ignore : un lancement en mmap n'est plus refusé pour elles. - Le refus sortait de « loki serve » avant tout chargement : l'interface affichait un chargement sans fin. modelLoadError le reconnaît et dit quoi faire (--load-mode mmap ou LOAD_GUARD=off). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f0d5711a1a |
Slots : corrections de relecture du lot 2 — une lecture d'un client ne prend plus le slot
Les proxys de Loki (/v1 et le relais) comptaient TOUTE requête d'un client comme une requête qui passe par le slot : un GET /v1/models ou une sonde /health (Open WebUI en envoie régulièrement) annulait le préchauffage en vol et retirait le tampon de la discussion. Avec PREWARM, COMPACT_CONTINUATION ou SLOT_PERSIST, la clé devenait inopérante dès qu'un client sondait le moteur. - engineProxyBegin : une lecture (GET, HEAD) reste comptée en vol, comme avant, mais n'avance pas le numéro des requêtes et garde le préchauffage ; une complétion de client garde le comportement d'avant. - README : avec PREWARM, SLOT_PERSIST ne garde presque rien (le préchauffage passe par le slot après chaque tour) — dit plutôt que découvert. Sans aucune de ces clés, rien ne change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
a94c752529 |
Optimiseur : corrections de relecture du lot 2 — verrou périmé reconnu, application interrompue défaite
Le verrou de l'optimiseur ne doit jamais bloquer quand aucune optimisation ne tourne, et ne jamais passer pour périmé quand elle tourne. Plusieurs identités de processus ne tenaient pas ces deux promesses hors Windows. - Linux : l'instant de démarrage est relatif au boot. Après une coupure, un service relancé au même moment du démarrage retrouvait PID et top : le verrou de l'ancien passait pour vivant et tout était refusé jusqu'à son retrait à la main. L'identifiant du boot le préfixe ; un verrou qui porte notre PID sans être l'un des nôtres est périmé. - Linux : un binaire remplacé par une mise à jour (« (deleted) ») faisait passer le propriétaire vivant pour mort. La mise à jour est de toute façon refusée pendant une optimisation (interface et loki update). - macOS : ps rend lstart dans la langue et le fuseau de l'appelant ; le web (launchd) et un terminal en français ne lisaient pas la même identité. LC_ALL=C et TZ=UTC. - Un verrou illisible tout juste créé (vide entre création et écriture) n'est plus retiré : seulement après 10 s. - loki tune : terminal fermé ou kill (SIGTERM, SIGHUP) annulent proprement, comme Ctrl-C ; Ctrl-C retrouve son sens aux questions de fin. - Application : la sauvegarde est notée dans le verrou ; un Loki tué avant la vérification remet l'ancienne version au redémarrage. Deux clics rapprochés ne lancent plus deux applications. Un échec de relance du vrai moteur se voit dans le résultat, plus seulement au journal ; un essai qui survit à son arrêt reste noté dans le verrou. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9d02592d4f |
Optimiseur : relecture — slot fixe sous SIDE_SLOT, moteur mort vu tôt, verrou réécrit sous Windows
- Avec SIDE_SLOT, les tours en profondeur d'un essai restent sur le second slot : la reprise du cache ne dépend plus du slot choisi par le moteur - Après application, un moteur qui meurt au chargement (OOM) ramène l'ancienne version en quelques secondes au lieu d'attendre le délai entier - La réécriture du verrou (essai en cours) réessaie quand Windows refuse de remplacer un fichier lu au même instant Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9bffff78c2 |
Optimiseur : loki tune et bouton « Optimiser », essais sans perte sur un moteur privé
Chercher à la main le bon micro-lot, les threads ou la marge --fit d'un preset demandait de dupliquer, basculer et comparer des bench complets un par un. L'optimiseur le fait sur un moteur d'essai, sans jamais toucher à config.env ni à ce que calcule le modèle, et n'écrit rien sans un clic. - Isolation : moteur principal arrêté puis relancé ; chaque essai est une copie de la configuration (LOKI_HOME/tune/run), lancée par « loki serve » sur 127.0.0.1 et un port libre, groupe de processus tué en sortie - Verrou exclusif inter-processus (LOKI_HOME/tune.lock, PID + démarrage + binaire) vérifié par serviceAction start/restart et par le chat, les tâches, bash_bg, /v1, le bench, la bascule et l'enregistrement de preset, GPU, clé d'API, moteur ; essai orphelin arrêté avant tout démarrage du moteur - Essais : lots, threads, délestage, marges --fit, files CUDA ; placement --fit et SPEC/CUDA_GRAPH_OPT/--backend-sampling seulement sur demande - EXTRA_ARGS jeton par jeton, liste blanche seulement ; ligne de commande de chaque essai composée à blanc et comparée à la référence (« dénature »), contexte, slots et cache KV recontrôlés une fois chargé - Mesure : bench complet du lot 1 à profondeur fixe ; score = durée d'un tour type (médianes de la télémétrie) ; gain > max(3 %, écart entre passages) - Application sur clic : copie du preset, ou preset actuel sauvegardé, réécrit clé par clé, vérifié par une sonde et rétabli en cas d'échec Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f87c7b615b |
MoE : avis de placement, copie en placement auto et garde du mode de chargement
Un MoE aux experts sur CPU se règle aujourd'hui à la main (-ot, --n-cpu-moe 40, UBATCH 512) sans que Loki dise ce que --fit ferait mieux, ni qu'un --load-mode none/mlock trop gros pour la RAM mène au swap ou à l'OOM (llama.cpp #26110). Rien n'est réécrit en douce : des avis, une copie sur demande, un refus seulement quand l'échec est certain. - moeNotes (pure, comme nglArgs) : experts placés à la main → --fit ne les place pas, et ne pas monter UBATCH seul (tampon plus gros sur chaque carte) ; placement auto, MoE plus gros que la VRAM, UBATCH ≤ 512 → « UBATCH 2048+ » ; moteur sans --fit → « garde --n-cpu-moe » ; --fit coupé par un autre -ot. Le détecteur cpuExperts ne compte un -ot que s'il vise les experts (exps) vers le CPU : celui de per_layer_token_embd n'en est pas. - « Dupliquer en placement auto… » (éditeur, /api/preset/autoplace) : COPIE du preset affiché, sans -ot des experts, --n-cpu-moe, --cpu-moe, -ngl, --tensor-split, --fit off, -b/-ub ni drapeaux de chargement ; NGL retiré, UBATCH 2048, BATCH 4096, --load-mode mmap ; CTX, cache KV, échantillonnage intacts. Refusée si --fit resterait inactif ou si CTX vaut 0. L'original n'est pas touché, la copie n'est pas activée. - loadModeRisk : none, mlock, dio, mmap+mlock (et --no-mmap, --mlock, LLAMA_ARG_*) face à la RAM effective (limite cgroup comprise), en comptant modèle moins VRAM (tout le modèle sur macOS) : avertissement au-delà de 80 %, refus au lancement au-delà de 90 % de la borne basse seulement ; LOAD_GUARD=off le lève. VRAM inconnue : jamais de refus. - Éditeur : avis sous « Experts MoE sur CPU » et sous « Chargement ». Ligne de commande et environnement du moteur inchangés (test de non-régression) ; presets externes ignorés. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
986a636c20 |
Placement : liaison PCIe des cartes et guide d'ordre dans l'éditeur, en conseil
Deux cartes inégales (5060 Ti + 3060) se placent par deux règles du moteur qui peuvent s'opposer : --fit remplit d'abord la DERNIÈRE carte, qui porte la couche de sortie, et les experts MoE en RAM sont recopiés au prefill vers la PREMIÈRE. Pour choisir l'ordre il faut voir la liaison de chaque carte ; l'éditeur n'en montrait rien. - detectGPUs lit aussi la liaison PCIe (génération et largeur, actuelles et maximales), le bus et l'horloge mémoire max, dans la même invocation de nvidia-smi. « [N/A] » vaut zéro ; un pilote qui refuse un champ fait retomber sur la requête historique (jamais de GPU perdu), un délai dépassé n'est pas relancé. Borné à 10 s. La largeur du bus mémoire n'existe pas dans nvidia-smi : absente. - /api/backends/devices : une seule lecture nvidia-smi par énumération complète mémoire manquante ET liaison (annotateDevices, pure), par nom de carte, CUDA seulement, rien pour deux cartes homonymes. La lecture des jauges (gpuStatsCached) n'est pas touchée. - Éditeur : liaison max par carte (l'actuelle et l'horloge en info-bulle), guide de placement dans l'ordre du moteur (--device compris), marges FIT_TARGET carte par carte, signalement d'un --tensor-split ou d'un CUDA_VISIBLE_DEVICES propre au preset, lien « inverser l'ordre » ; l'ordre choisi survit aux cases cochées. - Pas de bouton de mesure : comparer deux ordres demande deux rechargements et un ordre inversé peut manquer de VRAM — le guide explique la marche à suivre (copie du preset, bench complet sur chacun). - loki gpu affiche la liaison. Rien ne change dans la ligne de commande du moteur. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
889a85888d |
Persistance : un résultat d'outil supprimé pendant son écriture ne renaît plus
TestToolResultsSaveLoadDelete échouait de temps en temps en suite complète (1 fois sur ~300 en isolé). Vraie course dans le code, pas dans le test : deleteToolResultsFor retirait les résultats EN ATTENTE de l'écrivain différé, mais pas ceux qu'il avait déjà pris dans son lot. Si la transaction de suppression passait avant celle de l'écrivain, le résultat était écrit juste après avoir été effacé, et renaissait. En production, la suppression d'une discussion passe d'abord par forget + flush, ce qui masquait le problème ; mais forget non plus ne pouvait rien contre un lot déjà parti. - l'écrivain note les résultats du lot en vol ; dropToolRes (donc forget et deleteToolResultsFor) les marque annulés - l'écrivain vérifie l'annulation DANS sa transaction ; la suppression annule AVANT d'ouvrir la sienne : bbolt sérialisant les deux, soit le résultat est sauté, soit il est écrit puis effacé - annulations oubliées à la fin du lot : un nouveau résultat s'écrit - test déterministe (écrivain retenu en plein lot) qui échouait avant la correction ; suite complète passée 3 fois, TestToolResults ×400 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
5954d75118 |
Placement : SPLIT_MODE=tensor, parallélisme de tenseurs entre cartes, en opt-in
En découpe par couches (défaut), chaque carte traverse ses couches à son
tour. En mode tensor, chaque couche est coupée entre les cartes, qui
additionnent ensuite leurs morceaux : décodage plus rapide d'après
l'amont, prefill nettement plus lent. Sur deux GeForce en PCIe et une
boucle d'agent qui relit beaucoup, rien n'est acquis : expérimental,
off par défaut, et une longue liste de refus propres plutôt qu'un
moteur qui meurt en boucle. Sans la clé, ligne et environnement
identiques à l'octet près (test).
- détection : la liste littérale {none,layer,row,tensor} dans l'aide du
moteur — « tensor » seul y est partout (--tensor-split) ; absente =
aucun compagnon posé, note au journal
- GGML_CUDA_ALLREDUCE=internal sauf choix de l'environnement : NCCL
compresse en BF16 les réductions du prefill (avec perte) ; nccl
gardé s'il est posé, avec un avertissement ; note NCCL indisponible /
P2P à poser soi-même
- -ngl all, -ts au prorata de la VRAM totale (--list-devices, ordre du
moteur, --device compris), -fa on : chacun seulement si EXTRA_ARGS ou
une LLAMA_ARG_* ne l'a pas déjà ; CTX explicite exigé
- refus : KV autre que f16/bf16/f32 (KV_TYPE*, -ctk/-ctv, LLAMA_ARG_*,
jamais réécrit), --backend-sampling, -fa off, -sm à la main, poids ou
KV sur CPU, NGL partiel, SPEC, SIDE_SLOT, une seule carte ou non CUDA,
architectures exclues par llama.cpp et qwen4exp, preset externe
- pas de --fit en mode tensor : estimation poids + cache de CTX jetons
contre 90 % de la VRAM, refus au-delà, CTX jamais réduit
- files CUDA, CUDA_GRAPH_OPT et FIT_TARGET voient le -sm tensor ;
SLOT_PERSIST refusé avec la clé ; diagnostic du journal pour les
échecs propres au mode tensor
- README et configTemplate
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
539e36ea49 |
Spéculation : SPEC=ngram et mtp+ngram, n-grammes du contexte en opt-in
En mode Code, le modèle recopie sans cesse ce qui est déjà dans le contexte : chemins, diffs, arguments JSON, fichiers réécrits. ngram-mod de llama.cpp y cherche la suite des 24 derniers jetons et propose d'un coup les 48 à 64 suivants, sans modèle brouillon. La clé SPEC (off par défaut, inchangé) gagne deux valeurs : ngram, et mtp+ngram qui y ajoute la tête MTP. Même vérification exacte que MTP : distribution inchangée, mais pas le même texte au bit près (vérification par lots), donc on compare des sessions rejouées, pas des diffs. - forme explicite seulement : --spec-type ngram-mod --spec-ngram-mod-n-match 24 --spec-ngram-mod-n-min 48 --spec-ngram-mod-n-max 64 ; jamais --spec-default (TODO amont, contenu susceptible de changer avec le moteur) - garde-fou d'aide sur « --spec-ngram-mod-n-match » (pas le simple mot ngram-mod, encore listé par les moteurs d'avant le renommage) ; absent = SPEC ignoré, note au journal - mtp+ngram : --spec-type draft-mtp,ngram-mod seulement avec draft-mtp dans l'aide ET une tête MTP réelle (tenseur nextn ou MODEL_DRAFT) ; sinon n-grammes seuls, avec la raison — jamais « failed to create MTP context » en boucle - EXTRA_ARGS/LLAMA_ARG_* : mêmes exclusions qu'avant, plus --spec_type et tout --spec-ngram-* (--spec-type s'additionne sans prévenir) ; pour ngram seul, un --spec-draft-* fait aussi taire Loki - poids sur CPU (experts MoE, -ot, NGL partiel) : refusé tant que GGML_OP_OFFLOAD_MIN_BATCH (env ou OP_OFFLOAD_MIN_BATCH) ne dépasse pas le lot de vérification de 65 jetons, avec la suggestion OP_OFFLOAD_MIN_BATCH=128 ; avertissements pour un modèle plus gros que la RAM, les points de reprise d'un hybride, NGL imposé (logits) - avec ngram, une tête MTP ou MODEL_DRAFT inutilisés sont signalés - --spec-synth-len/--spec-synth-rates (et LLAMA_ARG_SPEC_SYNTH_LEN) : acceptation au hasard, avertissement au lancement ; Loki ne les pose jamais - télémétrie : /api/perf/summary donne draft_n, draft_accepted et draft_rate par nature de requête - UI : deux options du sélecteur de décodage spéculatif ; README et configTemplate - tests : forme explicite, garde d'aide, repli de mtp+ngram, exclusions, seuil d'offload, ligne inchangée sans SPEC, acceptation par nature Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
28ba44eb46 |
Slots : SLOT_PERSIST garde l'état de la discussion à la bascule de preset, en opt-in
Passer de A à B puis revenir à A relance llama-server deux fois, et la conversation de A est recalculée en entier au retour. Avec SLOT_PERSIST=on (off par défaut), Loki demande au moteur d'écrire l'état du slot 0 juste avant la bascule, et le recharge au retour avant le premier message de la discussion — seulement si tout concorde, sinon calcul normal, en silence. llama.cpp ne vérifie à la relecture que types et tailles : rien ne dit quel build ni quels réglages ont calculé ce cache. La clé de validité est donc l'empreinte de tout ce qui touche au calcul, prise par « loki serve » au lancement : ligne de commande complète (modèle, CTX, types KV, NGL, lots, gabarit, SPEC, EXTRA_ARGS…), LLAMA_ARG_*/GGML_*/CUDA_*, taille et date du modèle et de ses tranches, du projecteur, du brouillon, du binaire et de ses bibliothèques. Pas de cas « mise à jour du moteur » : elle change la clé. - --slot-save-path posé aussi pour SLOT_PERSIST accepté, sous les mêmes conditions de sécurité que l'isolation du lot 1 (boucle locale ou clé d'API) ; refusé avec le décodage spéculatif (le save ne garde pas le brouillon ; /slots speculative revérifié à chaque fois), des poids sur CPU, un --slot-save-path à la main ; la ligne reste alors celle d'avant - sauvegarde depuis l'interface ou une tâche, avant l'arrêt : le slot doit porter un tour de la discussion (tampon d'engineMarkMain), ≥ 4096 jetons, ≤ 8 Gio estimés, double de place libre ; nom provisoire, renommé seulement si aucune requête n'est partie pendant l'écriture - rechargement avant la première requête de la discussion (ou son préchauffage) : même clé de moteur, même discussion, slot 0 vierge (/slots sans id_task) ; une seule tentative, fichier retiré ; toute erreur = calcul normal - deux fichiers au plus ; clé retirée = tout effacé au lancement suivant ; SLOT_PERSIST préservé à la bascule comme HOST (sinon B effaçait l'état de A) - README : SIDE_SLOT, le cache KV plein ne déclenche jamais de compaction - tests : plan et refus, ligne inchangée, empreinte (clé d'API exclue, fichiers et réglages inclus), rotation, séquence save puis restore sur un faux moteur, refus à la sauvegarde et au rechargement, autre clé, défaut sans aucun appel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7a57322a62 |
Slots : SIDE_SLOT ouvre un second slot pour les travaux annexes, en opt-in
En --parallel 1, une vérification, un sous-agent, une tâche ou un bench prennent le slot de la discussion : son état part dans le cache RAM et en revient, ou se recalcule s'il n'y tient plus. Avec SIDE_SLOT=on (off par défaut), le moteur ouvre deux slots et la discussion garde le sien. Dimensionnement choisi pour qu'un débordement concurrent soit impossible par construction : cache KV NON unifié (--no-kv-unified) et -c 2×CTX, soit deux flux séparés de CTX jetons. Sous cache unifié, les deux slots partagent le pool et, plein, llama.cpp renvoie « Context size has been exceeded. » aux deux — que Loki prenait pour un débordement de la conversation. Chaque slot garde la fenêtre entière : ctxWindow et la compaction restent sur CTX, rien n'est raccourci. --cache-idle-slots ne vide les slots au repos que sous cache unifié : rien à régler. - lancement : refus (un slot, ligne d'avant, note au journal) si modèle + deux états dépassent 90 % de la VRAM, VRAM ou GGUF inconnus, poids sur CPU, moteur sans --no-kv-unified, PARALLEL≠2, ou -c/-np/-kvu/--no-kv-unified/ --kv-unified-per-slot/--cache-idle-slots dans EXTRA_ARGS (ou leurs LLAMA_ARG_*) ; note de VRAM en plus, avertissement si NGL imposé - routage id_slot seulement si /props annonce 2 slots d'au moins CTX jetons : 0 pour le tour, ses étapes, le préchauffage et le résumé en continuation ; 1 pour vérification, sous-agents, tâches, bench, résumé sur transcription - clients /v1 (proxy et relais) : corps réécrit en id_slot 1, quel qu'il soit - cohérence lot 1 : l'effacement de slot s'abstient (2 slots) ; une requête du slot 1 n'avance pas le numéro d'engineSlotHolds, la continuation de compaction reste possible après une vérification - « Context size has been exceeded. » sans nombre de jetons, deux slots en service : requête rejouée telle quelle, jamais compaction ni réduction - préchauffage permis sur les deux slots de SIDE_SLOT, vers le slot 0 - éditeur de preset : VRAM du second slot ou raison du refus - tests : ligne identique sans la clé, chaque conflit refuse sans changer la ligne, routage par nature, aucun id_slot sur un slot / preset externe / fenêtre partagée, rejeu sans compaction, proxy forcé, préchauffage Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c1d3757f23 |
Cache : KEEP_TURN_IMAGES, relecture — budget plein vérifié avant de ranger l'image
Le relais rangeait l'image sur disque avant de regarder si le budget des images gardées était déjà plein : un fichier écrit pour rien, élagué 24 h plus tard. - budget vérifié d'abord ; plein, l'image reste éphémère sans être rangée - README : sur un modèle hybride, le gain dépend des points de reprise du moteur après une image, à vérifier dans la télémétrie avant d'adopter la clé - test : budget plein, rien d'écrit dans chatimg Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f74f64ed90 |
Cache : KEEP_TURN_IMAGES garde les images d'outils et NUDGE_IN_TOOL range le rappel de budget, en opt-in
Une capture ou une image vue par see_image ne vivait que le temps du tour : au tour suivant elle manquait à l'historique, le préfixe en cache divergeait à elle et toute la boucle d'outils qui suivait était recalculée. Sur Qwen3.5, le rappel de budget en message user faisait de même pour le tour en cours : le nouveau message devient la « dernière question » et tout le tour est rendu autrement. Deux clés, off par défaut et étiquetées zone grise ; sans elles, requêtes identiques à l'octet près (testé). - KEEP_TURN_IMAGES : image gardée par référence (chatimg, chiffrée si la mémoire l'est), relue à l'identique avant d'être gardée, vision active revérifiée à chaque tour ; preset externe seulement s'il déclare la vision - coût mesuré par le moteur (écart de prompt_tokens moins le texte ajouté) ; image non mesurable = éphémère comme avant ; total sous 10 % de la fenêtre, la première qui dépasse et les suivantes du tour restent éphémères - compaction, réduction forcée et début ou milieu de tour au seuil retirent ces images d'abord (légende et imageLostMarker gardés), le résumé ne suit que s'il reste nécessaire ; clé retirée ou vision perdue : retirées au tour - relais marqué ImgRelay (persisté, retiré à l'envoi) : ni demande réinjectée ni preuve de demande servie, fil rouvert compris ; une image non gardée n'entre plus dans l'historique par une compaction en cours de tour - discussion seulement (ni tâche, ni sous-agent, ni vérification) ; fichier d'image rafraîchi à chaque usage, l'élagage de 24 h ne le prend pas - NUDGE_IN_TOOL : rappel de budget au bout du dernier résultat d'outil, même message persisté ; moteur local, sonde de gabarit « préfixe instable » pour ce modèle ; sinon, ou forme inattendue, message à part comme avant Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b0c53e32af |
Compaction : COMPACT_CONTINUATION, relecture — un refus mémorisé ne vaut que pour le même fil
Le refus mémorisé ne regardait que la taille du contexte. Il n'est évalué qu'au-dessus du seuil : une discussion vidée, éditée ou régénérée qui remontait dans la même plage de jetons voyait sa compaction sautée sur la foi d'un refus qui concernait un autre fil. - le refus garde l'empreinte de l'historique (celle de perfPrefix) ; seul un historique qui prolonge celui d'alors en profite, tout autre retente - testé : historique modifié ou raccourci, refus noté par une vraie compaction, filet réactif jamais bloqué Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2097c9f915 |
Compaction : COMPACT_CONTINUATION résume dans le prolongement du prompt en cache, en opt-in
Le résumé d'une compaction part aujourd'hui dans une requête à part — prompt du résumeur et transcription des anciens tours — que le moteur local calcule à froid : des dizaines de secondes sur un 27B, des minutes sur un MoE, à chaque compaction. Nouvelle clé COMPACT_CONTINUATION (off par défaut) : quand le slot porte encore le prompt de la discussion, la requête de résumé est celle du tour telle qu'elle est partie, suivie d'une seule demande de résumé ; le moteur ne calcule qu'elle. Sans la clé, requêtes de compaction identiques à l'octet près (prompt du résumeur comparé à une copie figée, testé). - vue MODÈLE pour tout ce qui est rangé : bornes, archives recall, demande réinjectée, garantie de réduction et sortie ne changent pas ; la vue d'envoi (turnViewDry, wireMessages, buildChatPayload) ne sert qu'à la requête, rien d'injecté n'entre dans l'historique (testé) - frontière recalée sur la vue envoyée (messages non système un pour un, vérifiés rôle par rôle), désignée par le nombre de messages gardés et le début du premier ; tout résumer avant, dater l'avancement à la frontière - mêmes règles de résumé (+ mode Code), même budget, température 0.2 sans l'échantillonnage du preset, enable_thinking=false ajouté aux arguments du tour, reasoning_effort du tour, tool_choice « none », sans flux - messages utilisateur de fin hors de la vue : pas en cache, et pas deux `user` d'affilée pour les gabarits stricts - slot vérifié : tampon posé par une étape de tour acceptée (llm_slots.go, sous le verrou du compteur en vol), perdu dès qu'une autre requête part — vérification, sous-agent, tâche, préchauffage, résumé, bench, /v1 — ou que le modèle ou la fenêtre changent ; relu à l'envoi - marge en jetons réels (dernier compte + non vu + demande + budget + 5 %) - repli sur la transcription au moindre écart : refus du moteur, réseau, appel d'outil émis (tool_calls décodés) ou écrit en texte, raisonnement seul, résumé vide ; refus du gabarit ou appel d'outil = suspendue pour le modèle jusqu'au redémarrage, deux échecs de suite aussi - avec la clé : pas de résumé quand même un vide ne réduirait pas de 20 % (borne exacte, avant tout archivage) ; après un refus faute de réduction, pas de nouvel essai avant +10 % de contexte, jamais à 90 % de la fenêtre, oublié quand le contexte baisse - réactif, fenêtre pleine, bouton manuel, tâches, sous-agents, terminal, preset externe : chemin d'avant ; télémétrie kind=compact avec la discussion Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
eb58f7982f |
Cache : PREWARM, relecture — commentaire du projet forcé rendu à son appel
Le différé du préchauffage s'était glissé entre le commentaire du projet forcé et setProjectOverride : il passe au-dessus, avec le sien. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
630e84cc08 |
Cache : PREWARM prépare le prochain tour pendant que l'utilisateur lit, en opt-in
Une compaction, un dernier message rendu autrement au tour suivant ou une tâche planifiée qui a pris le slot laissent au message suivant un recalcul inévitable : des secondes sur un 27B, des dizaines sur un MoE aux experts en RAM, avant le premier mot. Nouvelle clé PREWARM (off par défaut) : dès que le moteur local est libre, Loki lui envoie la requête du prochain tour suivie d'un message utilisateur « . », max_tokens 1, sans flux. Le moteur calcule le préfixe et pose un point de reprise au début de ce message ; le vrai tour ne calcule plus que le sien. Sans la clé, aucune requête de plus (testé). - assemblage partagé, contenu vivant : turnViewDry (même code que turnView, sans rien toucher à la discussion, décision PROJ_SNAPSHOT via projSnapDecide), wireMessages, turnReasoning et buildChatPayload, extraits de runChat ; corps identique à l'octet près à celui d'avant (matrice d'options et de modes, testée contre une copie de l'ancien code) - jamais devant un vrai travail : toute requête de Loki l'annule au départ (compteur de llm_slots.go, sous son verrou), sauf un tour de chat dont les messages sérialisés, outils et arguments du gabarit prolongent exactement le préfixe préchauffé - moteur local, un seul slot (/props total_slots), pas pendant un tour, une tâche, un bench, un travail annexe ni une requête en vol ; un seul à la fois ; pas si le prochain tour compactera, ni à moins de 10 min de minuit - requête brute : ni compaction, ni relance, ni effort appris, ni CtxUsed, ni stats ; erreurs lâchées (une ligne de journal par statut) ; rien persisté - déclencheurs : fin de tour sans file d'attente, fin de tâche (projet forcé levé, slot effacé) ; full = aussi changement de discussion après 3 s - capacités du dernier tour gardées en mémoire par discussion ; mode Code = rôle d'un message ordinaire, une demande de plan diverge et annule - télémétrie kind=prewarm ; la vérification du cache RAM après une tâche se fait sur lui Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4932999d5c |
Contexte : PROJ_SNAPSHOT fige le bloc projet par discussion, ses changements arrivent en mise à jour, en opt-in
Le contexte du projet (description, index mémoire, trackers, AGENTS.md) part en tête du premier message utilisateur, reconstruit à chaque tour : une page créée ou une valeur de tracker notée faisait recalculer toute la conversation derrière lui, 10 à 45k tokens. Nouvelle clé PROJ_SNAPSHOT (off par défaut) : avec on, chaque discussion garde une copie datée du bloc, renvoyée à l'octet près, et les changements arrivent en tête du message suivant dans un bloc <context_update from="loki">, rangé dans l'historique. Sans la clé, la requête est identique à l'octet près (testé contre l'ancien assemblage). - en-têtes figés « as of <date> » pour l'index mémoire et les trackers, sans « answer straight from this » ; ligne fixe du système, seulement avec la clé - mises à jour par type : +/~/- par page (clé « ](fichier) »), une ligne complète par tracker (clé = slug), texte COMPLET pour la description, AGENTS.md, ou un index dont la prose a changé — jamais de diff de prose - état annoncé structuré et persisté (ProjSnap, omitempty), instantané pris sur marqueur explicite : la première page d'un projet vide arrive en mise à jour, le premier message ne bouge pas - rafraîchi (blocs retirés de tout l'historique) quand le prompt change de toute façon : compaction début/fin/manuelle, compaction ou réduction en cours de tour (bloc vivant aussitôt, rangé comme instantané : pas de recalcul de plus), système ou outils modifiés, redémarrage de Loki, réglage moteur ou modèle, projet, nom, mode mémoire, mode Code, dépôt, textes des en-têtes ; et au-delà d'un seuil de mises à jour accumulées - mise à jour posée sous c.mu avec l'epoch, après la compaction de début de tour ; texte ou multimodal ; retirée du titre, de l'export JSON, de l'entrée du résumeur et de la tâche du vérificateur - loadFrom, Reset et le chargement remettent l'instantané à zéro ; clé retirée = nettoyage ; agent off = rien du projet ; tâches et presets externes inchangés ; un sous-agent ne voit pas le bloc du tour - ordre des trackers déjà déterministe (lot 1, test existant) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7c9aa04fd9 |
Raisonnement : REASONING_ECHO renvoie au moteur local la réflexion du modèle, en opt-in
Les gabarits Qwen3.5/3.6 rendent <think>…</think> pour chaque message assistant après la dernière question : c'est leur format entraîné. Loki ne gardait que le texte et les appels, donc à chaque étape d'une boucle d'outils le modèle relisait ses étapes précédentes avec des blocs vides, et le moteur recalculait le dernier message. Nouvelle clé REASONING_ECHO (off par défaut) : avec on, le raisonnement séparé par le serveur est gardé avec chaque message et renvoyé au même modèle. Sans la clé, rien n'est capturé ni envoyé : la requête est identique à l'octet près (testé). - Message.ReasoningContent (reasoning_content) + ReasoningModel, persistés ; seulement depuis reasoning_content du flux, jamais depuis le découpage « </think> » fait chez nous (rendu en double) - un seul point de sortie (echoMessages) : étiquette toujours retirée, raisonnement retiré pour une API externe, un autre modèle, un message sans texte ni appel, ou si la sonde dit que le gabarit ne le rend jamais - comptage : estimateTokens/compactBounds comptent ce qui part et que le gabarit rend (passé seulement si la sonde dit qu'il le garde, ou l'ignore) ; ctxAfter ne retire plus un raisonnement renvoyé - débordement : relance d'abord sans raisonnement, avant toute compaction ; shrinkToFit retire le raisonnement le plus ancien avant tout le reste ; le torse compacté le perd comme le résumé - erreur de gabarit (raise_exception, thinking, Failed to parse messages) : relance une fois sans raisonnement avant tool_choice none / outils coupés ; retenu pour le modèle si la relance passe - runBuilderTurn applique enfin NewHistory comme generate (compaction perdue pendant une passe de correction) ; forwardStream affiche la bannière - sonde de gabarit : nouveau verdict renders_reasoning - REASONING_PRESERVE (lot 1) inchangée, son interaction documentée Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3af481ff05 |
Télémétrie : une sonde du gabarit de chat, diagnostique et sans risque pour le cache
Les pistes de réutilisation du cache dépendent de deux faits que rien ne mesurait : le gabarit du modèle rend-il encore le raisonnement d'un tour passé, et le rendu d'un tour d'outil reste-t-il un préfixe exact quand un message utilisateur s'y ajoute ? La sonde pose ces deux questions au moteur local par POST /apply-template — un rendu sans état, qui ne prend ni slot ni place dans la file — et n'en tire que des verdicts oui/non/inconnu. Elle ne touche à aucune construction de prompt : Loki ne renvoie toujours aucun reasoning_content au modèle. Toute évolution qui voudrait s'en servir passera sa propre revue, et lira « unknown » comme « ne rien changer ». - moteur local seulement ; preset externe : aucune requête, rien d'affiché - jamais de complétion de repli : avec un slot, elle évincerait le cache - en tâche de fond après une complétion complète du fil principal, /health à 200, au plus une vérification par minute ; authHeader ; 3 s par requête - mêmes outils, chat_template_kwargs et reasoning_effort que la complétion - add_generation_prompt=false demandé au moteur ; un moteur qui l'ignore donne « inconnu » plutôt qu'un faux « instable » - tour d'outil bien formé (identifiant de 9 alphanumériques, résultat lié) - 404, 401, exception du gabarit, délai : inconnu ; 503 relancé - cache par build_info + modèle + empreinte du gabarit + forme de requête - verdict dans /api/perf/summary (champ template) et une ligne [tplprobe] au journal par verdict nouveau Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
09ee04037b |
Bench : corrections de relecture — niveau de raisonnement, préchauffage borné, verrou fiable
La relecture du bench en tâche de fond a trouvé quatre défauts qui le faisaient échouer ou s'interrompre là où il n'aurait pas dû, et une course entre la fin annoncée et le verrou rendu. - Niveau de raisonnement refusé par le gabarit (Qwen3.8 et « high ») : le bench rejoue une fois avec le niveau accepté, comme runChatTools, et retient la traduction. Il échouait sur ce 500 dans un processus neuf. L'erreur HTTP garde le corps entier : les niveaux acceptés sont cités au-delà des 300 caractères affichés. - Préchauffage borné au quart du contexte : -ub 4096 sur 8k de contexte envoyait un prompt plus grand que la fenêtre. - Changer de discussion n'annule plus le bench, et ne lui reprend pas le verrou. La libération suit le drapeau benching au lieu de l'epoch, qu'une bascule de fil bumpe. Reset arrête toujours le bench et rend le verrou. - Le verrou du chat est rendu avant que le statut ne dise « terminé » : un message envoyé aussitôt n'est plus refusé (et le test n'est plus instable). - Indication « possible thrash » mesurée sur les tours seulement, pas sur le prefill à froid qui lit légitimement les pages du modèle. - Interface : agrégats absents (omitempty) affichés à 0 au lieu de casser le rendu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
cf83f5f629 |
Bench : une mesure honnête à profondeur réelle, en tâche de fond
L'ancien bench ne lisait pas le statut HTTP, inventait un partage 15/85 du temps quand les timings manquaient (et l'enregistrait comme mesuré), tuilait un petit corpus qu'un brouillon recopiait, et ne disait rien du prefill à 30k ni du chemin où le cache est repris. Synchrone, il était coupé par les proxys (60-100 s) pendant que le moteur continuait, et un simple GET suffisait à le lancer. - Tâche de fond : POST /api/bench (202, 405 sur GET, 409 si occupé), /api/bench/status pour la progression, /api/bench/cancel ; chaque requête au moteur porte le contexte annulable. - Verrou de génération tenu pendant toute la mesure : chat, tâches et compaction reçoivent un refus clair ; les clients /v1 un 503 avec Retry-After ; /slots occupé (client externe, CLI) refuse aussi. - Mode rapide par défaut : préchauffage jeté + la ligne courte, sur le chat avec gabarit, raisonnement et échantillonnage du preset, seed fixe. - Mode complet (bouton « bench complet », loki bench --full) : prefill à froid à D = min(CTX/2, 32k, ce qui laisse tenir les tours), 16k si des poids tournent sur CPU, puis 3 tours user → assistant → user de code jamais vu. Reprise du cache lue dans cache_n, jamais supposée ; note pour les hybrides (points de contrôle). Pas d'ignore_eos. - Rien n'est enregistré sans réponses 200 et timings réels, ni pour un résultat partiel (budget de 6 min par requête, contexte plein). - Empreinte enregistrée (configuration + CUDA_VISIBLE_DEVICES + protocole) ; les anciennes mesures retombent sur le nom du modèle. Types de cache KV et build du moteur affichés, KV quantifié signalé (zone grise). - Linux : indication « possible thrash » (read_bytes, VmRSS), jamais enregistrée. - Effacement du slot en fin de bench inchangé (engineSideJob, différé : il tourne aussi sur erreur et annulation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9f6bd725e6 |
Stockage : corrections de relecture — le remède Unraid décrit tel qu'il existe
« Exclusive access » n'est pas un réglage qu'on passe à Yes sur la page du partage : c'est un état, que Unraid 6.12 accorde quand « Permit exclusive shares » est activé et que le partage vit tout entier sur un pool, sans stockage secondaire (/mnt/user/<partage> devient un lien vers le pool). La consigne précédente envoyait chercher une option introuvable. - conseil, compose et README : le vrai chemin (Global Share Settings, mover vers le pool puis Secondary = None, « Exclusive access : Yes »), et redémarrer le conteneur, Docker ne résolvant le lien qu'au démarrage ; - un seul chemin par montage fuse.shfs : /data/models répétait /data ; - l'encart de l'UI, permanent tant que la cause dure, devient masquable (localStorage, pour ce texte seulement — un autre conseil réapparaît). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
056f307983 |
Stockage : Loki signale un /data ou /models servi par le FUSE d'Unraid
Sur Unraid, /mnt/user/… n'est pas un disque mais shfs, un démon FUSE : chaque fsync de loki.db et chaque page d'un gros MoE mmappé relue depuis le disque (modèle plus gros que la RAM) le traverse, à chaque token. Rien n'est perdu ni altéré, mais le décodage ralentit — sans que rien ne le dise. Loki ne déplace rien : changer le chemin hôte d'une installation donnerait un /data vide. Il le voit et le dit, sur un ton d'information : - sys_storagefuse.go lit /proc/self/mountinfo (type lu après le séparateur « - », montage le plus long qui contient le chemin) pour LOKI_HOME et chaque dossier de modèles ; Linux en conteneur seulement, mis en cache une minute puisque /api/status est interrogé en boucle ; - conseil en jaune au démarrage et champ « hint » de /api/status, affiché en encart discret, distinct du bandeau rouge de perte de données ; - compose Unraid et README : « Exclusive access » recommandé (même chemin, FUSE court-circuité), /mnt/<pool> en option avancée avec migration manuelle et mise en garde sur un pool inexistant (RAM). La détection de thrash du cache de pages est laissée de côté : elle exige un signal majflt calibré par modèle sur le serveur. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
667e340e57 |
Persistance : corrections de relecture — un résultat d'outil ne forge plus de discussion
Relecture de l'écrivain différé (chat_persist.go) : l'ordre, la suppression et les bascules tiennent ; trois écarts de comportement corrigés. - saveToolResult et la télémétrie de generate lisaient la clé brute de la discussion active ; passés à convEnsureActive, ils pouvaient en CRÉER une (tâche de fond sur base neuve → discussion vide dans la liste). Nouveau convActiveID : cache chaud, sinon la clé en base, jamais de création. - Un résultat d'outil confié après la suppression de sa discussion restait en mémoire pour toujours (l'écrivain l'écarte, la copie ne partait plus) : il n'est plus retenu. - Vidage de l'écrivain avant « verrouiller la mémoire » (sinon l'envoi tout juste fait ne touchait le disque qu'au déverrouillage) et avant le restart systemd après MAJ (SIGTERM ne laisse rien finir). Tests : résultat d'une discussion supprimée ni écrit ni retenu ; base neuve, saveToolResult reste sous « nosession » sans créer de discussion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c3005f5b56 |
Persistance : le fsync de la discussion ne retarde plus le premier token
StartTurn persistait AVANT de lancer la génération : un marshal, puis deux commits bbolt (contenu, puis index), soit deux fsync et plusieurs ouvertures de base — 26-30 ms mesurés sur un NVMe Windows, bien plus sur un /mnt/user d'Unraid ou un disque de parité, payés à chaque message avant que la requête ne parte vers llama-server. Même facture au milieu d'un tour (vérification du mode Code) et pour chaque résultat d'outil coupé (« voir plus »). - chat_persist.go : un écrivain unique et ordonné. L'instantané reste pris sous c.mu (images → références, marshal, identifiant de la discussion) ; seule l'E/S part en différé. Le dernier instantané de chaque discussion l'emporte (numéro pris sous c.mu), les lots sont fusionnés en UNE transaction : contenu + index ensemble, résultats d'outils compris. - Seuls StartTurn, la persistance en cours de tour et les résultats d'outils sont asynchrones. Fin de tour, reset, bascules, compactage manuel restent synchrones et attendent tout ce qui précède ; la suppression écarte puis attend les écritures qui la visent (plus de discussion ressuscitée). - Discussion active gardée en RAM, créée sous verrou (plus de double identifiant sur base neuve) et changée sous c.mu avec le contenu : un instantané ne peut plus écrire l'ancien fil sous le nouvel identifiant. - « Voir plus » servi depuis la mémoire tant que le résultat n'est pas écrit ; verrouillage vérifié avant de rendre un id. - En plein tour, la base reçoit le journal sous sa forme de fin de tour (compactLog, version pure de compactLogLocked) ; la mémoire n'est pas touchée. - Vidage de l'écrivain avant redémarrage, « Quitter », exec et (dé)chiffrement. Le contexte vu par le modèle ne change pas : il lit c.Messages en mémoire, les résultats complets d'outils et la compaction du journal ne servent qu'à l'UI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9b2e974942 |
Moniteur : corrections de relecture — un nvidia-smi pendu ne fige plus les jauges
gpuStatsCached tient son verrou pendant la requête : c'est ce qui fait partager une seule lecture aux onglets. Mais la requête n'était pas bornée, et le code le dit ailleurs (nvidiaGPUCount) : un pilote coincé peut faire pendre nvidia-smi. Avant le cache, chaque nouvelle requête relançait son propre nvidia-smi et les jauges revenaient avec le pilote ; avec le verrou, un seul processus pendu bloquait /api/vram pour tous les onglets jusqu'au redémarrage de Loki. - nvidiaSmiQuery : CommandContext borné à 10 s (large pour une première lecture lente sans mode persistant), WaitDelay d'une seconde. Au-delà, une erreur ordinaire, retentée au délai normal du cache. - Le déchargement profite de la même borne : une lecture pendue devient une mesure ratée, que gpuSettle sait déjà sauter. - Test : la vraie requête, binaire absent du PATH, rend bien exec.ErrNotFound — la seule erreur que le cache garde une minute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4f34694400 |
Moniteur : un seul nvidia-smi pour tous les onglets, aucun pour un onglet caché
Chaque onglet ouvert (et chaque téléphone) interrogeait /api/vram toutes les 3 s, et chaque requête lançait son propre nvidia-smi — y compris depuis un onglet en arrière-plan que personne ne regarde, pendant que llama-server génère. Rien de tout cela ne touche au modèle : seules les jauges sont concernées. - gpuStatsCached : lecture partagée de 2 s, verrou tenu pendant la requête pour que des appels simultanés attendent la même lecture. nvidia-smi introuvable (Mac, CPU seul) mémorisé une minute ; une autre erreur se retente au délai normal. - Seul handleVram passe par le cache. Le déchargement (lecture « avant » et gpuSettle) garde des lectures fraîches : deux valeurs égales servies par le cache feraient conclure gpuSettle à tort. Le cache est vidé après un déchargement. - UI : statut, VRAM et RAM ne sont plus interrogés dans un onglet caché ; lecture immédiate au retour. - Tests : cache (réutilisation, erreur, binaire absent, appels simultanés) et échantillonneur du déchargement qui contourne le cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3dff7e0e04 |
Flux : corrections de relecture — le « +N » d'une écriture ne recompte plus tout le corps
Chaque événement de frappe (un par ligne) appelait bodyLineCount sur le corps ENTIER pour remplir body_lines : un reste de coût quadratique, léger mais inutile, puisque argPreview tient déjà le compte des sauts de ligne. - argPreview.lineCount : même règle que bodyLineCount (saut de ligne final sans ligne de plus), en temps constant. - Le test de décodage par morceaux vérifie l'égalité avec bodyLineCount à chaque préfixe (fuzz compris). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f1f6cbe4ea |
Flux : l'écriture d'un gros fichier ne coûte plus un temps quadratique côté Go
Pendant qu'un modèle tapait un write de 120 Ko, chaque morceau faisait relire et redécoder tout le JSON des arguments, puis republiait le corps ENTIER à chaque ligne : 250 Mo de flux SSE, autant de tas vivant dans le journal, et près de 8 s de CPU volées au décodage quand des experts tournent sur le processeur. Même travers pour la détection des appels d'outils écrits en texte, qui repassait toutes les regex sur toute la réponse à chaque jeton. Rien de ce que voit le modèle ne change : les arguments exécutés restent entiers, la passe complète de fin de tour aussi. - argPreview : lecture incrémentale de l'argument affiché et du corps, même règle que previewArgDone (barre oblique coupée gardée en attente) ; arguments accumulés dans un strings.Builder, cur.Function.Arguments recalé sur lui à chaque morceau. - Événement de frappe : seules les 40 dernières lignes (4 Kio au plus) du corps, avec body_lines (vrai « +N ») et body_tail ; l'UI affiche « … » et garde le repli sur le décompte local. - textualToolCallFrom : ne relit que la fin, depuis un vrai début de ligne avant la fin du balayage précédent, en reculant sur les suites que les motifs embarqués peuvent traverser. Surcharge retry_patterns : balayage complet, comme avant. - Direct SSE : les événements trouvés à un réveil partent en une écriture (lots de 128 Kio / 256 événements au plus), un sceau par événement en E2E. - Tests : fuzz d'argPreview contre previewArgDone, équivalence fenêtre / balayage complet au morceau près, corps borné de bout en bout, ordre des lots ; bancs d'essai. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
eaf5e313d9 |
Cache : corrections de relecture — la ligne MCP et les descriptions d'outils partagent un seul format
mcpPromptLine relisait le préfixe « [MCP: <serveur>] » des descriptions en le réécrivant à la main : changer le format dans mcpTools aurait fait disparaître la ligne en silence. Un nom de serveur contenant « ] » y était aussi coupé. - mcpTagDescription pose le préfixe, mcpToolServer le relit : un seul endroit. - mcpToolServer retient la coupure dont la forme assainie est celle du nom d'outil — « a] b » reste « a] b ». - Les tests qui appellent EnabledTools isolent $LOKI_HOME : la configuration MCP de la machine de test (et ses connexions) ne fausse plus le cas « sans outil MCP » ni le budget du préambule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7dd319a058 |
Cache : la ligne MCP du préambule ne manque plus au premier tour après un démarrage
Le préambule système était bâti (InjectSkills → baseSystemPrompt) AVANT que runChat n'appelle EnabledTools, donc avant que mcpTools n'ouvre les connexions. mcpPromptLine lisait le pool encore vide : le premier tour après un démarrage partait sans la ligne MCP, le second avec — tout le prompt à recalculer pour une ligne. Elle comptait en plus les outils masqués par l'utilisateur, et s'affichait pour le planner, qui ne reçoit aucun outil MCP. - prepareTurn calcule les outils UNE fois par tour, puis le préambule à partir d'eux ; runChatTools les reprend tels quels (pas de second passage par mcpEnsureAll, qui retentait deux fois un serveur en panne). - mcpPromptLine se déduit de cette tranche : seuls les outils réellement envoyés sont comptés, et rien n'est annoncé sans outil MCP. - trackerList départage les égalités d'horodatage par nom puis slug : la liste part dans le contexte, un ordre tiré au sort changeait le prompt. - Le commentaire de tasks_run.go ne prétend plus que le préfixe d'une tâche égale celui du chat (dossier de travail et taskCaps diffèrent). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9263df404d |
Cache : corrections de relecture — un rappel de loki ne laisse plus deux messages user d'affilée
Persister les rappels ouvrait trois façons de coller deux `user` dans l'historique, celles-là même qu'appendNudge voulait éviter : sur un gabarit à alternance stricte, chaque tour suivant aurait échoué. - Fin de tour : un rappel resté sans réponse (stop, erreur) ou suivi d'un ajout en cours de réponse est retiré avant persistance (dropStrayNudges), comme avant sa persistance. - Compaction : la queue ne commence plus sur un rappel ; la vraie demande réinjectée devant elle lui était collée. Elle recule d'un groupe d'outils. - isLokiInjected ne se contente plus du préfixe « [system] » : un message de l'utilisateur qui commence ainsi n'est plus pris pour un rappel (sa demande était sautée par la compaction, le vérificateur et le titre). - Relance tool_choice « none » : pas de repli après un stop, qui partait sur un contexte annulé et affichait une erreur. - Tests : appel par le protocole et refus 4xx sous « none » (et rien d'exécuté), frontière de compaction, nettoyage de fin de tour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
38b488515a |
Cache : les rappels de loki et la relance après un 500 ne recalculent plus la conversation
Le rappel de budget d'outils et la relance « pensé sans agir » partaient au moteur sans entrer dans l'historique : au tour suivant, le fil divergeait juste avant eux et toute la boucle d'outils qui suivait était recalculée. Le modèle relisait en prime une histoire qu'il n'avait jamais vue. La relance après un 500 (appel d'outil mal parsé) retirait les outils et modifiait le message système : tout le prompt repartait de zéro, deux fois. - Rappels persistés tels qu'envoyés (appendNudge), sauf derrière un autre message user : éphémères là, pour ne pas casser à chaque tour les gabarits à alternance stricte. - Ils restent reconnaissables (isLokiInjected) : la compaction ne les réinjecte pas comme demande en cours et ne les prend pas pour la preuve qu'une demande a été servie ; la réduction forcée coupe d'abord aux vraies demandes ; le vérificateur, l'export, le titre et le résumeur les sautent ou les présentent comme note du système. - Relance après un 500 sur le llama-server local : mêmes outils, même message 0, tool_choice « none » et la consigne au bout du dernier message, jamais persistée. Nouveau refus, appel tenté malgré tout ou réponse vide : repli une fois sur le chemin historique. Preset externe inchangé. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
72ba8e0fb6 |
Compaction : corrections de relecture — une balise </think> citée n'ampute plus le résumé
cleanSummary coupait toujours au DERNIER </think>. Un résumé de session Code qui cite la balise (un parseur, un gabarit — sessions sur Loki même) perdait donc tout ce qui la précédait, sans erreur ni trace : exactement la perte que le commit précédent voulait supprimer. - Le raisonnement ne se retire qu'en tête : un bloc <think>…</think> qui ouvre la réponse (plusieurs à la suite au besoin), ou un </think> sans <think> avant lui (gabarit qui ouvre le bloc dans le prompt). - Un bloc cité en milieu de texte reste tel quel. - La coupe par le filet (API qui ignore max_tokens) est tracée elle aussi. - Tests : CTX fixé (le filet en dépend), réponse du faux moteur derrière un mutex, cas de balises citées et de blocs multiples. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e14ead98c4 |
Compaction : le résumé n'est plus amputé de son état d'avancement
Le résumé de compaction était coupé net à 2200 caractères (≈ 550 tokens) alors que max_tokens l'autorise jusqu'à ~1600 tokens. Le prompt du résumeur place l'ÉTAT D'AVANCEMENT en dernier : c'était donc exactement ce dont l'agent a besoin pour reprendre qui tombait, et les tokens décodés au-delà étaient jetés. - La borne passe à compactSummaryBudget()×6 caractères : un simple filet pour une API qui ignorerait max_tokens, qui borne déjà la sortie. - finish_reason=length : le texte est gardé, marqué « […] » et tracé dans le journal ([compact] résumé coupé par max_tokens…). - Un <think> ouvert en tête et jamais refermé, ou un contenu vide à côté d'un reasoning_content, est une erreur : l'appelant retombe sur le torse dégraissé au lieu d'installer du raisonnement brut comme mémoire. - Tests : table de cleanSummary, et un résumé de 7000 caractères qui revient intact du moteur. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
26fc348506 |
Contexte : corrections de relecture — la garde de marge ne compacte plus en boucle, et le preset externe compte comme avant
La garde de marge de génération réclamait 1,2 × la plus longue génération récente, sans plafond. Une étape de 40 k sur une fenêtre de 65 k (ou de 20 k sur 32 k, sans budget de raisonnement) demandait plus de place que l'historique fraîchement compacté n'en laisse : la garde repartait à chaque étape, et chaque fois résumait le résumé précédent. - Garde : jamais avant la moitié de la fenêtre. Au-delà, le rejeu sur « length » reste le filet. - Preset externe : le complément « messages arrivés depuis la mesure » ne s'applique plus. Son CtxUsed garde le raisonnement, qui couvrait déjà ce complément ; l'ajouter le faisait compacter plus tôt qu'avant. - Journal [ctx] : l'estimation d'avant compaction (début de tour, en tour) n'est plus comparée au compte d'une requête compactée, ce qui donnait de faux écarts. - Tests : génération énorme juste après compaction, seuil de 50 % pour toutes les fenêtres, comptage externe contre local. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d6023ef8a0 |
Contexte : le raisonnement jamais renvoyé ne compte plus, et la compaction ne part plus trop tôt
CtxUsed valait usage.prompt_tokens + généré, raisonnement compris. Or Loki ne renvoie jamais ce raisonnement au modèle (Message n'a pas de champ pour lui) : la requête suivante pesait 1 à 8 k jetons de moins que le compte, et la compaction, qui perd de l'information, partait vers 44-47 k au lieu de 49 k sur une fenêtre de 65 k. Rien ne change dans les requêtes : seul le compte qui décide de compacter. - Comptage : seulement les morceaux reasoning_content séparés par le llama-server local, remis à zéro à chaque tentative. Le <think> découpé chez nous reste dans le message renvoyé pendant le tour, il n'est pas retiré ; l'API externe garde l'ancien calcul. Un morceau vaut au plus un jeton : on ne peut que sous-estimer, le sens sans danger. - Début de tour : le message utilisateur (et la file) arrivé depuis la dernière mesure s'ajoute en estimation, comme en cours de tour. - Vérificateur : sa trace isolée écrasait CtxUsed avec sa petite taille, et la fin de tour décidait sur ce chiffre-là. Plus maintenant ; la jauge de l'UI ne bouge pas non plus et suit le même calcul que le serveur. - Marge de génération : le compte gonflé offrait une marge par accident. Elle est remplacée par une vraie garde — compacter si 1,2 × la plus longue génération récente ne tient plus dans la fenêtre. Plancher et marge seuls ne devancent jamais le seuil de 75 %. - Fenêtre pleine en plein raisonnement (finish « length » au-delà du seuil) : compaction puis étape rejouée, au lieu du nudge « arrête de raisonner ». - Journal [ctx] : estimation contre compte réel au-delà de 2 % d'écart, chaque « length » et chaque nudge, pour vérifier qu'ils n'augmentent pas. - Le seuil reste à 75 % : la réserve fixe proposée (toolResultMax/3 + 6 k) laissait trop peu de place sans budget de raisonnement ni max_tokens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
18a723a671 |
Télémétrie : corrections de relecture — compaction aussi tolérante qu'avant, pas d'alerte de cache sur une API externe, seuil qui suit EXTRA_ARGS
La relecture du relevé par complétion a trouvé quatre écarts, tous d'affichage ou de robustesse ; rien ne touche aux requêtes ni au contexte. - Compaction : la réponse lue d'un bloc passait de Decoder à Unmarshal, plus strict (un octet parasite après le JSON faisait échouer une compaction qui passait). Retour au Decoder, et perfWire fait de même. - API externe : son cache suit ses propres règles, sans slot ni points de reprise à surveiller ici. Plus de ligne ambre « recalculés » pour elle ; le relevé reste dans l'anneau. - Seuil d'alerte : même priorité qu'au lancement — -cms d'EXTRA_ARGS, puis LLAMA_ARG_CHECKPOINT_MIN_SPACING_NT, puis CKPT_MIN_STEP ; -ub d'EXTRA_ARGS avant UBATCH. - UI : « recalculés après sous-agent, client /v1 » au lieu des identifiants internes (subagent, foreign). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
80b7793773 |
Télémétrie : chaque complétion dit enfin ce qu'elle a repris du cache, recalculé et accepté du brouillon
Jusqu'ici, impossible de savoir si une ligne volatile s'était glissée dans le prompt, si une mise à jour du moteur avait cassé les points de reprise ou si l'acceptation du MTP s'était effondrée : le chunk final de llama.cpp porte ces chiffres (cache_n, draft_n, cached_tokens), on les jetait. Lecture seule : aucun champ ajouté aux requêtes, et le comptage du contexte (usage.prompt_tokens → CtxUsed → compaction) ne change pas. - perf_log.go : décodage à part et tolérant (perfWire) — un compteur mal typé ne jette plus le chunk final ni ne fait échouer une compaction ; cached_tokens, strictement entier dans streamChunk, y déménage aussi. - Inconnu n'est pas 0 : pointeurs, et l'UI garde « prefill N tok » quand le moteur ne dit rien de son cache. - Nature (main, subagent, verify, task, compact, bench, foreign) portée par le contexte, pas par Caps ; TTFT au premier delta de tout type. - Perte de cache = total précédent − cache_n, seulement quand les messages prolongent strictement ceux de la complétion précédente de la même discussion et de la même nature (empreintes cumulées) ; jamais sur un flux coupé. Ce qui s'est intercalé (sous-agent, client /v1, bench) est nommé. - Anneau de 5000 entrées en mémoire, sans texte ; GET /api/perf/summary (derrière la clé) : taux de cache, recalcul par tour et par nature, médianes pp/tg par profondeur, acceptation du brouillon. - Ligne [perf] sur stderr seulement avec LOKI_PERF_LOG. - UI : « prefill X nouveaux / Y en cache », ambre au-delà d'un seuil relevé sur un modèle hybride (espacement des points de reprise). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3ff56e01db |
Moteur : corrections de relecture du MTP opt-in — le contrôle après chargement voit enfin le journal, et un second lancement ne prend plus le jeton du premier
La relecture de
|
||
|
|
3a6ad6f23b |
Moteur : décodage spéculatif MTP en opt-in — tête détectée dans le fichier, garde-fous VRAM, et un essai raté ne se rejoue pas
Une tête MTP (Qwen3.6/3.8, intégrée ou publiée à part en mtp-*.gguf) accélère
le décodage sans rien changer à la sortie : chaque jeton émis est tiré par
l'échantillonneur du modèle cible, un jeton du brouillon n'est gardé que s'il
coïncide. Le prix est ailleurs — 1 à 2 Go de VRAM, un prefill parfois plus
lent, une fonction très récente du moteur — d'où l'opt-in : rien ne change
pour un preset existant.
- SPEC=off (défaut, clé absente comprise) / auto / mtp. La tête se reconnaît
au TENSEUR blk.{N-1}.nextn.eh_proj (backend_gguf.go), comme llama.cpp : la
clé nextn_predict_layers seule ne prouve rien.
- MODEL_DRAFT : résolu comme MMPROJ, mais introuvable ne bloque pas le
lancement. Tête à part → -md + --spec-type draft-mtp explicite (llama.cpp ne
devine que sur la première tranche) ; autre brouillon → draft-simple, sinon
chargé en VRAM pour rien.
- auto seulement si --fit place tout (ni couches chiffrées, -ts, -ot, experts
sur CPU, -sm row, --fit off, -dev), contexte chiffré (fit pourrait sinon le
réduire), pas de vision, build officiel ≥ 11009, jamais qwen4exp. mtp impose,
avec un avertissement.
- Aide du moteur lue à chaque fois : draft-mtp et --spec-draft-n-max requis ;
--draft/--draft-max jamais émis. EXTRA_ARGS (--spec-type, -md, -hfd,
--spec-default…) et LLAMA_ARG_SPEC_* gardent la main.
- Tirage greedy fixé (exact pour toute chaîne). probabilistic seulement avec
SPEC=mtp, refusé avec mirostat ou adaptive-p. SPEC_N_MAX → --spec-draft-n-max.
- Jeton de tentative : « loki serve » le pose avant de lancer, le process web
l'efface dès que le moteur répond (sans page ouverte). Resté au lancement
suivant, même preset, moteur et build → auto coupé et dit. Couches poussées
en RAM après chargement : même verdict. Les erreurs MTP/brouillon du journal
ont leur message.
- Éditeur : « auto » et « MTP » écrivent SPEC, « non » écrit SPEC=off ; champ
Brouillon ; la recherche HF propose la tête MTP du dépôt, décochée.
- Tests : table de specArgs (gardes, sauts, brouillons, tirage), place avant
EXTRA_ARGS, cycle du jeton sur une vraie base, lecture du journal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
7f49310b7f |
Moteur : corrections de relecture des points de reprise — un slot de plus compte, et un « --version » coincé ne bloque plus le lancement
La liste des points de reprise de llama-server est PAR SLOT : la garde de RAM de l'espacement d'office ne comptait qu'une liste, et sous-estimait d'autant le pire cas avec PARALLEL > 1. Et « loki serve » lit désormais le build du moteur avant de le lancer (hybrides seulement) : sans délai, un binaire coincé à l'initialisation de ses backends bloquait le lancement, là où binHelp, lui, était déjà borné. - ckptSlots : --parallel d'EXTRA_ARGS, sinon PARALLEL, sinon 1 ; « auto » ou illisible compté pour 4. Le pire cas devient points × slots × poids. - engineBuildOf borné à 15 s (WaitDelay pour un descendant qui garde la sortie) : passé le délai, build inconnu, ni avis ni drapeau. Profite aussi au panneau Moteur. - Tests : PARALLEL=2 garde l'espacement, PARALLEL=4 et --parallel 4 le retirent ; table de ckptSlots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
dd27b81af0 |
Moteur : points de reprise des hybrides protégés sur les moteurs anciens, et la version précédente gardée après une mise à jour
Avant b10864 (PR #28302), llama-server effaçait un point de reprise trop proche du précédent même quand la liste avait de la place : sur un hybride (Qwen3.5/3.6, Qwen3-Next), une reprise retombait jusqu'à ~8 k jetons en arrière, recalculés à chaque tour d'outil. Un point de reprise est une copie exacte de l'état récurrent : rien de ce que voit le modèle ne change, seul le temps de prefill et la RAM hôte. Aucune mise à jour du moteur ici. - Build cru seulement pour un moteur officiel (image, téléchargé, précompilé) et au-dessus de 5000 : un compilé en clone superficiel (build 1) ou un fork n'a ni avis ni drapeau. --version gardé par binaire, taille et date. - Avis « moteur trop ancien » dans le panneau Moteur et au lancement d'un hybride. - Opt-in CTX_CHECKPOINTS (--ctx-checkpoints) et CKPT_MIN_STEP (--checkpoint-min-step, > 0 : 0 laisserait l'éviction FIFO jeter le point du début de la conversation). Gardes séparées : -ctxcp/--ctx-checkpoints/ --swa-checkpoints et -cms/--checkpoint-min-step, plus LLAMA_ARG_*. - D'office : --checkpoint-min-step 2048 seulement sur un hybride lu dans le GGUF, build officiel < 10864, aide qui connaît le drapeau, aucun réglage de l'utilisateur, points de reprise actifs, modèle sous 70 % de la RAM et 32 points sous le quart de la RAM libre. Sinon l'avis seul ; sur un MoE mmappé trop gros, conseil CTX_CHECKPOINTS=8 à 16. - REASONING_PRESERVE=on|off → --reasoning-preserve / --no-reasoning-preserve, seulement si la clé est posée et que l'aide le connaît. Rien par défaut : Loki ne renvoie pas la réflexion passée, et aucun choix global ne garde le rendu de tous les gabarits (Qwen3.6 contre Qwen3.8). - Mise à jour du moteur : la version téléchargée qui tournait avant n'est plus supprimée ; le panneau propose d'y revenir sans réseau. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c72467ce4c |
Moteur : corrections de relecture de l'isolation des travaux annexes — un slot que le travail n'a jamais pris n'est plus effacé
Un sous-agent, une vérification, une tâche ou un bench qui échoue avant que le moteur ne le serve (erreur avant l'envoi, refus 4xx, arrêt immédiat) laissait le slot 0 tel quel : il portait encore la conversation, que l'effacement jetait alors sans qu'elle soit dans le cache RAM — recalcul complet garanti, soit exactement ce que l'isolation devait éviter. - engineServed() : runChat (réponse 200 du moteur local) et le bench le notent ; un travail annexe n'efface que si le moteur a servi au moins une requête de Loki depuis son début (finishSideJob, testable sans moteur). - Les prompts d'un travail annexe ne sont plus retenus comme « la conversation » par noteEnginePrompt : deux vérifications de suite comparaient sinon la conversation au prompt du vérificateur, et le conseil pouvait se tromper. - CACHE_RAM et CACHE_ISOLATE figurent dans le modèle de configuration commenté (loki config). - Éditeur : une valeur fixée par EXTRA_ARGS ou LLAMA_ARG_CACHE_RAM (-1, 0) ne s'affiche plus comme « défaut du moteur ». Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3565b594ea |
Moteur : cache de prompts dimensionné et travaux annexes isolés — la conversation n'est plus recalculée après un vérificateur ou un sous-agent
llama-server garde en RAM hôte une copie exacte des états de slot qu'il quitte (KV, état récurrent, points de reprise, brouillon MTP) et la recharge octet pour octet. Mais son défaut de 8 Gio ne tient pas une conversation de 30 à 65 k jetons à côté de l'état d'un vérificateur, d'un sous-agent, d'une tâche ou d'un bench : à la requête suivante il évince la conversation pour sauver l'annexe, et tout est recalculé (30 à 80 s sur un 27B). Rien de ce que voit le modèle ne change ici : seul le bruit de découpage des lots, comme le cache_prompt actuel. - CACHE_RAM (Mio ; vide/auto, nombre passé tel quel, -1, 0) → --cache-ram, seulement si l'aide du moteur le connaît. Loki se tait devant -cram d'EXTRA_ARGS et LLAMA_ARG_CACHE_RAM. L'auto ne descend JAMAIS sous le défaut : il agrandit seulement un modèle tout-GPU (VRAM NVIDIA connue, aucun poids ni KV sur CPU, NGL complet), d'après l'état mesuré dans le GGUF (2,5 × KV à CTX + état récurrent et points de reprise des hybrides), plafonné à 30 % de la RAM (limite cgroup comprise) et à la moitié de la RAM libre. - --slot-save-path LOKI_HOME/slots (0700, purgé au lancement) uniquement si le moteur est en boucle locale ou protégé par clé, et si le dossier existe. Les proxys /v1 et du relais refusent désormais toute action /slots (405). - engineSideJob efface le slot 0 APRÈS le sous-agent, la passe de vérification, la tâche planifiée et le bench (pas après la compaction : rien à y gagner). Synchrone, borné à 2 s, et seulement si : moteur local, build ≥ 8660 lu dans /props, total_slots == 1, slot 0 au repos, aucune requête de Loki en vol (compteur tenu par le chat, les résumés, le bench et les proxys). CACHE_ISOLATE=off le coupe. - usage.prompt_tokens_details.cached_tokens : si la conversation revient avec moins de la moitié en cache, conseil (une fois) de relever CACHE_RAM. - Éditeur de preset : champ « Cache de prompts » à côté d'UBATCH, avec la valeur auto calculée par le serveur (/api/preset/cacheram). - Lecteur GGUF : embedding_length, head_count et dimensions ssm.*. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d028e81ce2 |
Modèles : corrections de relecture du lecteur GGUF — v2, première tranche sans tenseur et octets corrompus testés
La relecture n'a trouvé aucun défaut dans le lecteur lui-même : bornes, versions, tranches, cache et vérification du début des données tiennent. Trois cas réels restaient pourtant sans test. - GGUF v2 : même disposition que v3, désormais vérifié avec v1 et gros-boutiste. - gguf-split --no-tensor-first-split : la première tranche ne porte que les clés, aucun tenseur ; la tête MTP est trouvée dans la suivante. - Un octet corrompu à chaque position de l'en-tête (v1 et v3, valeurs 0xFF, 0x7F, 0x00) : le lecteur rend la main sans jamais tomber dans le filet du panic rattrapé, qui ne doit rester qu'un filet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
0e841c26bd |
Modèles : lecteur des métadonnées GGUF
Plusieurs réglages du moteur dépendent de ce que le fichier contient vraiment
(tête MTP, têtes KV par couche, couches récurrentes d'un hybride) et Loki ne
le devinait qu'au nom du fichier. ggufMeta lit l'en-tête, les clés et la
table des tenseurs, jamais les poids. Aucun appelant pour l'instant : rien ne
change au lancement.
- Champs retenus : architecture, block_count, nextn_predict_layers,
head_count_kv (valeur unique ou tableau par couche), key/value_length,
expert_count, context_length, full_attention_interval, hybride (une clé
<arch>.ssm.*).
- Tête MTP reconnue comme llama.cpp la reconnaît : le tenseur
blk.{block_count-1}.nextn.eh_proj.weight, cherché dans toutes les
tranches. La clé nextn seule ne prouve rien (tête publiée à part).
- Robuste : chaque longueur bornée par ce qui reste du fichier, compteurs et
imbrication plafonnés, GGUF v1/v2/v3 et gros-boutiste, panic rattrapé,
fichier coupé (en-tête ou début du dernier tenseur) refusé, tranche
manquante refusée.
- Cache par chemin, taille et date de chaque tranche ; les erreurs ne sont
pas gardées.
- Tests sur des GGUF synthétiques écrits par le test : hybride avec MTP, tête
absente ou mal placée, tranches, v1 et gros-boutiste, toutes les
coupures, fichiers aberrants, cache.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
c4f051a0e9 |
Moteur : corrections de relecture des garde-fous de fidélité — les variables LLAMA_ARG_* et le glissement par défaut des anciens moteurs se voient aussi
Les garde-fous ne lisaient qu'EXTRA_ARGS et KV_TYPE. Or llama.cpp applique ses variables LLAMA_ARG_* avant la ligne de commande : un conteneur lancé avec LLAMA_ARG_CACHE_TYPE_K=q8_0 ou LLAMA_ARG_CACHE_REUSE=256 changeait les calculs sans un mot. Et un llama-server d'avant --context-shift glisse le contexte PAR DÉFAUT : il jetait des jetons alors que rien n'était écrit nulle part. - Type de cache effectif : variables, puis KV_TYPE*, puis EXTRA_ARGS, la source la plus forte est nommée dans la note ; warnSlowKV suit. - --context-shift et --cache-reuse lus aussi dans LLAMA_ARG_CONTEXT_SHIFT et LLAMA_ARG_CACHE_REUSE ; moteur ancien (aide sans --context-shift) : on dit qu'il glisse et que --no-context-shift l'en empêche. Aucun drapeau ajouté. - Vision reconnue aussi par --mmproj d'EXTRA_ARGS et LLAMA_ARG_MMPROJ. - Placement figé lu par tensorOverride : --n-cpu-moe 0 ne compte plus, --n-cpu-ffn et LLAMA_ARG_N_CPU_MOE si. Même règle dans l'interface. - Test du paquet : les étiquettes json:"cache_prompt" des structures sont aussi refusées hors du benchmark. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |