Le chip modèle du composer était décoratif (pastille orange fixe) alors
que le TopBar montrait le vrai état de chargement. Le sélecteur complet
(liste + pastille GPU/CPU/à charger/préchargement) vit maintenant dans
la carte du chat, menu vers le haut.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
La relance après « pensée seule » n'agissait qu'à la fin de la
génération : un modèle thinking pouvait ruminer des minutes (jusqu'à
épuiser num_predict) avant qu'elle n'intervienne — vécu comme « aucune
réponse » en mode plan.
Pensée > 12 000 caractères sans aucun contenu ni appel d'outil : la
génération est interrompue immédiatement et la relance repart.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Les noms MCP à tirets (resolve-library-id) cassaient le tool-calling :
modèles et grammaires mélangent tirets et underscores -> « Tool not
found ». Les noms exposés sont assainis en underscores avec table de
correspondance vers le vrai nom, et l'appel tolère les deux formes.
read_file sur un dossier disait « fichier introuvable » : message
explicite « c'est un dossier — utilise list_dir ».
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le fallback SPA renvoyait index.html pour /favicon.svg : l'icône
n'apparaissait jamais. Les fichiers statiques racine existants sont
maintenant servis tels quels, le reste retombe sur index.html.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le déplacement de la préparation (plan, recall RAG) dans le flux SSE
laissait un silence total pendant le chargement d'un gros modèle : le
reverse proxy coupait la connexion (« Connexion interrompue pendant le
chargement du modèle »). Avec la réflexion active, l'appel de plan
laissait en plus le modèle penser — silence encore plus long.
- ping SSE toutes les 10 s pendant la préparation du contexte
- plan / auto-critique / résumé : think=False (repli automatique si le
modèle refuse le paramètre) — un appel utilitaire ne réfléchit jamais
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Avec la réflexion activée sur les longues tâches, le modèle brûlait tout
son budget de génération à penser : done sans contenu ni appel d'outil,
la boucle s'arrêtait et la tâche restait inachevée.
- itération « réflexion seule » : relance avec consigne d'agir ; si ça
recommence, think est coupé pour la fin du tour (+ notice)
- marge num_predict >= 6144 quand la réflexion est active
- la pensée reste affichée dans l'UI mais n'est plus renvoyée au modèle
(elle regonflait le contexte à chaque itération)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Les résultats d'outils dévoraient le contexte du modèle : sortie shell
tronquée aveuglément à 4000 c. (bruit gardé, erreur parfois coupée),
gros fichiers lus en entier.
- run_shell : succès = 12 dernières lignes ; échec = lignes d'erreur
+ fin de sortie, répétitions dédupliquées (« ligne ×N »)
- read_file : fenêtres de 200 lignes avec marche à suivre
(start_line=N pour la suite, grep_search pour cibler)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
« Corrige les bugs » partait à Aider sans contexte (quel fichier ? quel
projet ?) et le chemin agent ignorait quels fichiers existaient — le
modèle collait alors le code en chat au lieu de modifier le fichier.
- moteur code : récap de session (demande initiale + dernières demandes
+ fichiers touchés) préfixé à l'instruction ; fichiers de la session
passés à Aider quand aucun n'est cité
- chemin agent : liste des fichiers du workspace + fichiers de la tâche
injectée chaque tour en système
- directive renforcée : « ne colle JAMAIS le code corrigé dans ta
réponse sans l'avoir écrit dans le fichier »
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sur une reprise (« ajoute un bouton », « continue »), le routeur ne voyait
que le message courant : score trop bas, jamais le moteur code, et le
modèle décrivait les changements sans les appliquer.
- routage contextuel : si le tour précédent était du code (engine ou
outils write_file/edit_file/code_task), les suites courtes partent au
moteur code (is_code_followup)
- chemin agent sur session code : directive système « AGIS avec les
outils, ne décris jamais sans appliquer »
- fichiers cités dans le message et présents au workspace transmis à
Aider (travail direct, sans deviner via la repo map)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sur un long tour, les gros résultats d'outils (MCP 8 Ko, shell 4 Ko)
saturaient num_ctx et Ollama tronquait silencieusement le DÉBUT de la
conversation : le modèle perdait la consigne et « oubliait » sa tâche.
- élagage : les résultats d'outils des itérations passées sont compactés
(350 c. + marqueur), le dernier lot reste intact
- num_ctx 16384 par défaut (migration v6 : les profils restés sur les
anciens défauts 4096/8192 sont montés, les valeurs perso respectées)
- serveur MCP avec paramètre requis manquant (SEARXNG_URL) : refus clair
au démarrage au lieu d'un échec cryptique à chaque appel
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
L'auto-check séparé dans la boucle agent doublonnait _verify_written et
signalait à tort les fichiers écrits par morceaux (mode append).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ollama reloaded the chat model mid-message because plan/summary/router
calls sent divergent runner options (no num_ctx/num_batch) and omitted
keep_alive — the main cause of perceived slowness.
- share one keep-alive httpx.AsyncClient for all Ollama calls
- unify runner options (runner_options) + keep_alive on every model
call, embeddings included
- drop the blocking LLM routing fallback (pure lexical heuristic)
- run RAG recall + plan + code-model pick in parallel inside the SSE
stream, after the start event
- RAG cosine scoring off the event loop; cache /api/tags 30s and
nvidia-smi 5s; frontend polls 2s->5s, warm poll backoff, dedup
config fetch
feat: working session menu in TopBar (switch/create/rename/delete)
feat: workspace file deletion (DELETE /api/files + UI trash buttons)
docs: recommended Ollama env vars (KEEP_ALIVE, MAX_LOADED_MODELS...)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Favicon now matches the LokiMark topbar icon instead of an unrelated
arrow glyph. New /api/system/stats endpoint (psutil + nvidia-smi)
polled every 2s and shown in the topbar next to the Ollama status.
Le bloc de code avait un texte gris fonce (text-ink-2) sur fond sombre apres
le passage au theme clair -> illisible. Texte repasse en clair (on-dark),
bordure noire 3px + ombre dure pour coller au theme neo-brutaliste.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Certains modèles « thinking » ne renvoyaient que du raisonnement, sans reponse
finale -> erreur. Nouvel interrupteur global `think` (Reglages > Generation) :
- think=false envoie `think:false` a Ollama pour desactiver le raisonnement
- repli automatique si le modele refuse le parametre (does not support thinking)
- message d'erreur mis a jour pour pointer vers l'interrupteur
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
UI : reskin complet vers un theme neo-brutaliste clair (bordures noires 3px,
ombres dures, accent orange, polices Press Start 2P + DM Mono).
- tailwind.config / index.css / index.html : palette, polices, ombres, scrollbars
- TopBar, ActivityBar, LeftPanel, ChatPanel, PreviewPanel, SettingsView,
ToolCard, ModelSelector, Icon : restyle complet
Chat : panneau « Raisonnement » repliable et redimensionnable affichant le
thinking de l'agent en direct (diffuse depuis le backend, persiste dans meta).
Robustesse Ollama : les echecs de generation de parseur d'outils
(« Unable to generate parser for this template ») declenchent desormais le
repli automatique en conversation simple sans outils, au lieu d'un 400.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Frontend
- MessageContent: rendu Markdown complet (react-markdown + remark-gfm) avec
blocs de code dans un cadre + bouton Copier, et styles thematises (titres,
listes, gras, liens, tableaux, citations).
- ChatPanel: affiche sous chaque reponse de l'agent la vitesse (tokens/s) et le
nombre de jetons generes / en entree.
- PreviewPanel: iframe en sandbox="allow-scripts" pour que le JS des pages
generees s'execute (animations, canvas) tout en gardant une origine opaque.
- Icon: ajout CopyIcon / CheckIcon.
Backend
- agent: cumule les metriques Ollama (eval_count, eval_duration,
prompt_eval_count) et calcule les tokens/seconde, emis dans l'evenement final.
- chat: persiste les stats dans meta et les renvoie au client.
- agent_config: l'invite systeme par defaut demande un formatage Markdown.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- agent_config: num_gpu auto (-1) par défaut au lieu de forcer un nombre
de couches codé en dur (RTX 3060), qui faisait basculer Ollama sur CPU
quand la config ne tenait pas en VRAM. num_gpu/main_gpu ne sont transmis
que si l'utilisateur force explicitement une valeur (>= 0).
- agent_config: migration v4 remettant a -1 les profils deja enregistres
avec un num_gpu fige.
- agent: la boucle de reparation d'appel d'outil reinjecte son rappel en
role "user" au lieu de "system" (les templates Gemma/Mistral refusent un
message system hors tete -> 400 "System message must be at the beginning").
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ollama signale certains échecs en cours de génération (OOM, contexte trop
grand, débordement sur CPU) via une ligne JSON {"error": ...} avec un statut
HTTP 200. La boucle de streaming ne lisait que message.content / tool_calls /
done : ces lignes étaient ignorées, le flux se terminait avec un contenu vide,
et l'UI n'affichait rien — l'agent semblait "ne pas répondre".
- ollama_client: OllamaError + détection des chunks {"error": ...} (chat & pull),
corps de réponse remonté sur erreur HTTP, timeout de connexion court
(échec rapide si Ollama injoignable) avec lecture sans limite, et parsing
JSON tolérant aux lignes partielles.
- agent: capture d'OllamaError -> événement "error" affiché à l'utilisateur.
- docker-compose: config GPU NVIDIA pour le service Ollama embarqué (sinon CPU).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- config.py : overrides GPU_VRAM_MB / GPU_NAME
- ollama_client.py : méthode show() (/api/show)
- autotune.py : détection GPU (nvidia-smi/rocm-smi/env), profil modèle et calcul
du num_ctx optimal via estimation du cache KV
Module isolé, pas encore exposé via route ni UI (sans impact sur l'app).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Le conteneur tournait en utilisateur non-root (uid 10001) et ne pouvait pas
écrire dans /data et /workspace montés depuis /mnt/user/appdata (détenus par
root sur Unraid), provoquant un crash au démarrage (connexion refusée).
On revient à root par défaut ; durcissement possible via user: au niveau compose.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
- Sépare le port hôte (HOST_PORT, défaut 8717) du port interne du conteneur (8080)
- docker-compose.yml : mapping ${HOST_PORT:-8717}:8080
- docker-compose.unraid.yml : 8717:8080
- .env.example : HOST_PORT=8717
- README : références de port mises à jour
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
- .github/workflows/docker-publish.yml : build + push de ghcr.io/r0m1k3/loki
(linux/amd64, tags latest + sha, cache GHA) à chaque push sur main
- docker-compose.unraid.yml : utilise l'image préconstruite (plus de build/git
sur Unraid, simple pull)
- README : instructions Unraid mises à jour (image GHCR, visibilité du package)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
- docker-compose.unraid.yml : stack prête pour Unraid (Compose Manager),
build depuis le repo cloné dans appdata, volumes /mnt/user/appdata/loki,
OLLAMA_HOST à adapter, healthcheck
- README : section Installation sur Unraid (détection auto des modèles Ollama)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Backend :
- tools.py : web_search (DuckDuckGo HTML sans clé, ou SearxNG via SEARX_URL) et
run_shell (confiné au workspace, sortie bornée, timeout)
- agent.py : run_shell sensible -> émet tool_confirm et ne s'exécute pas tant que
l'utilisateur n'a pas validé (confirm_shell)
- agent_config.py : web_search/run_shell désactivés par défaut, flag confirm_shell
- routes/shell.py : POST /api/shell/run exécute une commande validée
- routes/chat.py : relaie l'événement tool_confirm, passe confirm_shell
Frontend :
- streamChat : événement tool_confirm
- store : pendingShell + approveShell/rejectShell (réinjecte le résultat à l'agent)
- ChatPanel : carte de validation de commande (Approuver / Refuser)
- SettingsView : toggles web_search/run_shell, marqueur sensible, switch confirm_shell
- ToolCard : glyphes web_search/run_shell, statut 'à valider', aperçu d'argument
Tests : run_shell confiné, gate de confirmation (commande dangereuse non exécutée),
route shell, parser DuckDuckGo.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N