mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-16 11:49:43 +02:00
2bbf0ba76dddd68ba8574fbb97ae15eb31a283df
16
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
199d7f1e99 |
Chat : compactage sans redite, file multi-appareils, bascule par identifiant
Repris d'AJEAN 0.17.4. - Compactage : la dernière demande du torse n'est plus réinjectée quand la queue contient déjà un message utilisateur (le modèle répondait une seconde fois à une vieille question), ni quand le résumé a échoué (elle est déjà dans le torse dégraissé et réapparaissait après ses propres résultats d'outils). - Le texte écrit avant un appel d'outil n'est plus rangé deux fois dans l'historique du modèle (message tool_calls ET réponse finale) : du contexte gaspillé à chaque tour d'outil. - Deux appareils qui envoient en même temps : le second message part en file au lieu d'un 409. Une tâche planifiée garde le refus. - Un raisonnement qui reprend après du texte de réponse ouvre une nouvelle bulle sous la réponse au lieu de remplir l'ancienne, repliée au-dessus. - Bascule de preset par identifiant : le numéro seul visait un autre preset quand la liste avait bougé sur un autre appareil. Le numéro reste accepté. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2c36fa6d2c |
Mémoire : un mode par projet, et un quatrième — « recherche »
Repris d'AJEAN 0.13.12. PAR PROJET Le mode mémoire était un réglage global de config.env. Il vit désormais sur le projet (champ mem_mode) : un chantier de code peut couper la mémoire pendant qu'un projet perso la garde proactive. Un projet sans réglage propre — tous ceux d'avant — retombe sur l'ancien MEM_MODE global : rien ne change tant qu'on n'y touche pas. L'API /api/memory et `loki memory` agissent sur le projet actif ; l'UI le dit, et se recharge déjà au changement de projet. AUTO, EN DEUX SAVEURS - « auto, injectée » (always, le défaut) : l'index des pages est en tête de conversation. La consigne dit maintenant d'y lire directement la bonne page ; mem_search ne sert plus qu'à chercher par contenu. Avant, on injectait l'index ET on exigeait une recherche préalable — un appel d'outil par tour pour retrouver ce que le modèle avait sous les yeux. - « auto, recherche » (nouveau) : rien d'injecté, l'IA cherche avant chaque tâche. Contexte plus léger, démarrage plus rapide. memProactive regroupe les deux là où seul « proactif » compte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
fa69dac77f |
Chiffrement de la mémoire, snapshots, sauvegarde chiffrée en fichier
Reprise d'AJEAN (mem_crypto/mem_vault/mem_store/mem_io/mem_migrate/ mem_snapshots/mem_health/mem_fsutil + backup_bundle), adaptée à Loki. Chiffrement à enveloppe : une DEK tirée une fois chiffre les données en AES-256-GCM ; elle est enfermée dans un coffre par une KEK dérivée en Argon2id. Ce qui ouvre le coffre : la clé de pilotage de l'appareil (le serveur n'en a que l'empreinte, il ne peut pas ouvrir seul) ou la clé de récupération donnée une fois. La DEK ne vit qu'en RAM. Périmètre chiffré, choisi pour Loki : les pages mémoire, les discussions (journal ET index, qui porte les titres), les blocs archivés au compactage — du verbatim de conversation — et les trackers. Pas les buckets de réglages : le coffre lui-même y vit, les chiffrer serait une boucle. Verrouillé, rien n'est écrasé : putStoreBytes REFUSE d'écrire du clair par-dessus du chiffré, la liste des discussions se lit vide et les pages s'affichent « 🔒 chiffré ». Le déverrouillage recharge la discussion et rattrape ce qui serait resté en clair. Une migration interrompue reprend au démarrage, un snapshot est pris avant chaque bascule, et aucune donnée n'est supprimée avant relecture vérifiée de son remplaçant. Piège corrigé au passage : chiffrer À L'INTÉRIEUR d'une transaction bbolt se bloquait sur le verrou de la base (memEncActive relit la config, donc la base). L'état du chiffrement est désormais résolu AVANT la transaction (memEncoderNow), qui ne reçoit plus qu'un encodeur pur. Sauvegarde : le paquet chiffré {mémoire, presets, réglages} s'exporte et s'importe en FICHIER (/api/backup/export, /api/backup/import). La sauvegarde vers le relais ajean.link n'est pas reprise — c'est le service de l'auteur amont ; ici le fichier reste chez soi. Le dossier mémoire n'était déjà plus joignable qu'aux outils mem_* : c'était la condition de ce chiffrement (un `cat memory/…` aurait rendu du binaire). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6CAgoLJzufeA8rZTSpSpY |
||
|
|
00b2350fb9 |
Navigateur piloté, images redressées : reprises d'AJEAN
L'amont (AJEAN 0.15) donne à l'IA le contrôle d'un navigateur ; Loki embarquait déjà un Chromium pour `web_screenshot` sans jamais le piloter. Contrôle du navigateur (computer_use.go, computer_cdp.go, browser_grid.go, portés d'AJEAN) : l'IA ouvre une page en CDP, en reçoit les éléments interactifs NUMÉROTÉS et agit par numéro (browser_open/snapshot/find/click/ type/key/scroll). Aucune vision requise — un petit modèle texte s'en sort. Avec un projecteur chargé s'ajoutent browser_screenshot (image quadrillée) et browser_click_xy. Interrupteur dédié (Réglages, `loki computer`, /api/computer), sous le mode agent : cliquer et taper dans une page sont des actions réelles, même niveau de confiance que bash. Adaptation au conteneur : chromePath cherche D'ABORD le Chromium de Playwright (PLAYWRIGHT_BROWSERS_PATH, /opt/pw-browsers), le seul navigateur de l'image — sinon la fonctionnalité se déclarait absente là où le navigateur est présent. LOKI_CHROME force un chemin, LOKI_CU_HEADFUL ouvre une vraie fenêtre. Préparation des images (web_upload_orient.go, porté d'AJEAN) : l'orientation EXIF est cuite dans les pixels — le projecteur l'ignore et voyait les photos de téléphone couchées — et le grand côté ramené sous 1568 px. Appliquée aux pièces jointes, à see_image et aux captures. Dédup des appels d'outils : bash, bash_bg, bash_tail, see_image et les browser_* ne sont plus court-circuités sur un appel identique. Relancer la même commande après avoir modifié un fichier est légitime, et un outil qui porte une image dans un message à part renvoyait « [déjà fait] » SANS l'image — le modèle tournait en boucle. Mode code : le builder ne publie plus de lui-même (pas de commit/push/reset/ rebase ni de redémarrage de service sans demande explicite), reprise de la leçon d'AJEAN 0.15.4 ; l'inspection en lecture seule reste encouragée. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6CAgoLJzufeA8rZTSpSpY |
||
|
|
b5904907e8 |
Reprise réseau, presets externes, see_image
Trois apports repérés chez AJEAN (v0.13.8) et OpenFox (2.0.118), portés et adaptés à Loki. ## Reprise réseau du tour (llm_retry_net.go) La requête de complétion partait une fois : un Do() qui échoue ou un statut d'erreur tuait le tour. Les messages d'erreur le disaient eux-mêmes — « réessaie dans quelques secondes » — autrement dit on demandait à l'utilisateur de refaire à la main ce que le code pouvait faire seul. Une tâche planifiée tombée pendant un redémarrage du moteur échouait pour de bon, sans personne pour recliquer. Trois reprises consécutives, 0,8 → 1,6 → 3,2 s, plafonnées, interruptibles par un /stop. La règle de sûreté ne souffre pas d'exception : on ne rejoue que TANT QU'AUCUN OCTET N'A ÉTÉ DIFFUSÉ, sinon la moitié de la réponse déjà chez l'utilisateur serait dupliquée. Le compteur repart à zéro dès qu'une réponse arrive. 500 n'est pas un statut de reprise : c'est ce que llama.cpp rend pour un appel d'outil malformé ou un prompt trop long, deux échecs déterministes que les filets sémantiques traitent déjà. Restent les codes qui disent « pas maintenant » : 429, 502, 503, 504. ## Presets externes (backend_external.go, web_external.go) Un preset avec EXTERNAL=1 route le chat vers une API OpenAI-compatible distante (OpenAI, Groq, OpenRouter, un vLLM sur une autre machine) au lieu du llama-server local. C'est un preset COMME UN AUTRE : même liste, même bascule, même prompt système par preset. La différence ne vit qu'à deux endroits — l'inférence (resolveChatEndpoint) et la bascule, qui arrête le moteur local au lieu de le redémarrer. La clé du serveur local ne part jamais chez un tiers : chaque endpoint porte la sienne. La clé du preset n'est jamais renvoyée en clair à l'interface, et un champ vide ne l'efface pas — il faut y avoir touché. Une fenêtre dédiée plutôt que l'éditeur habituel : un modèle distant n'a ni quantification, ni couches GPU, ni moteur. Un bouton teste la connexion avant d'enregistrer, et rend le message de l'API plutôt que le JSON brut. Le résumé de compactage part au même endroit que le chat : le laisser taper le moteur local aurait cassé toute compaction sur un preset externe. ## see_image (chat_vision_tool.go) Loki savait voir une pièce jointe et une capture qu'il venait de prendre, mais pas un fichier qui dort sur le disque : « regarde ~/photos/bug.png » n'avait aucune réponse, `read` rendant des octets binaires. L'outil charge l'image et la réinjecte dans un message utilisateur multimodal — même chemin que les pièces jointes. Même règle ÉPHÉMÈRE que les captures (et non celle de l'amont, qui persiste l'image) : l'image va dans le tour en cours, pas dans l'historique. Un base64 persisté repartirait à chaque tour et finirait par dépasser la fenêtre pour de bon. Le marqueur de perte à la compaction existait déjà mais n'offrait qu'un recours, « reprends la capture » — ce qui enverrait photographier une page web alors que l'image perdue est un PNG du disque. Formulation généralisée. ## Au passage toolCallLabel est extrait de runChat. Cette table nom d'outil → argument a une double fonction — libellé affiché ET argument principal — donc un outil absent s'exécute sur une chaîne vide : see_image répondait « chemin de fichier manquant » quoi qu'on lui passe, sans que rien d'autre ne bronche. Une table pareille se teste. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0129sffVC43rezAXUMQuzUog |
||
|
|
17f8fa8f34 |
Mémoire longue (recall), projets et trackers
Trois apports repris d'AJEAN 0.12.9 → 0.13.5, adaptés au fork. MÉMOIRE LONGUE DE LA CONVERSATION (chat_recall.go) Le compactage résumait, donc perdait. Chaque gros bloc du torse est désormais ARCHIVÉ verbatim sous un identifiant court (r7…) dans bbolt AVANT d'être résumé ; le résumé cite l'id, et le modèle le rappelle avec recall(id) ou le retrouve par mots-clés avec recall_search. Le contexte reste plat, l'archive grossit sur disque. En mode code, un fichier lu ou un diff produit tôt dans la session n'est plus perdu au compactage suivant. Au passage : garde-fou anti-résumé-dégénéré, budget de résumé indexé sur la fenêtre, queue ramenée à 20 % (compacter plus large ne coûte plus de perte), et fin de l'épinglage du 1er message user — le modèle répondait à l'ancienne demande au lieu de continuer la tâche en cours. PROJETS (projects.go) Un projet cloisonne une mémoire, ses discussions et ses trackers. La couture est memoryDir(), qui pointe sur le projet actif : tout le code mémoire en hérite sans le savoir. Migration automatique au premier démarrage (memory/*.md → memory/generale/, discussions et tâches orphelines rattachées). Une tâche planifiée vise un projet et l'exécution le force, pour qu'une veille n'écrive pas dans la mémoire du chantier affiché à l'écran. TRACKERS (tracker.go) 3e type de mémoire : les données datées qui s'accumulent. On ne les lit jamais en entier — consultation par niveaux (vue d'ensemble → année → mois → événements), et la dernière valeur de chaque tracker est donnée d'emblée au modèle, qui répond sans appeler l'outil. Aussi : index MEMORY.md tenu par le CODE et injecté en tête de conversation avec la description du projet (le modèle ne peut plus le désynchroniser) ; prompt système rattaché au PRESET et non plus global — stocké en base, pas dans le .env, qui ne saurait pas porter un texte multiligne. Deux correctifs du lot précédent voyagent ici, faute de pouvoir séparer les fichiers : msgText signale la présence d'une image au compactage, et le garde-fou « pensé sans agir » passe à deux relances (nudgeCount/maxNudges). Le paquet UI est regénéré dans le commit suivant, qui touche les mêmes sources. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
86d711e772 |
Sélecteur de modèle qui charge vraiment ; % de chargement qui bouge
Quatre retouches d'interface : - Le sélecteur de l'en-tête liste maintenant les MODÈLES du disque (groupe « Modèles (.gguf) ») en plus des presets : en choisir un le charge — POST /api/models/use écrit MODEL seul (contexte, NGL et échantillonnage conservés) et redémarre le service en arrière-plan. Sans preset créé, le sélecteur n'offrait aucun choix. - Pourcentage de chargement : sur un redémarrage à chaud, le modèle est déjà dans le cache disque — llama-server ne lit rien (read_bytes reste à 0) et la pastille passait de « 0 % » à « prêt » sans jamais monter. On prend le plus avancé de read_bytes et de la mémoire résidente (VmRSS), qui grandit cache ou pas. - Discussions triées par date de CRÉATION (récentes en tête) : une discussion garde sa place, écrire dans un vieux fil ne le fait plus remonter. - Bouton Réglages ancré en pied de barre latérale, juste au-dessus du moniteur Performance — toujours au même endroit, quel que soit le nombre de discussions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
0f58ad7b49 |
Tâches planifiées : l'IA travaille toute seule (repris de l'amont AJEAN)
Portage des v0.9.9 → v0.10.2 de l'amont, la dernière vraie fonctionnalité qui nous manquait. Une consigne, une fréquence (« @every 2h », « tous les jours à 9h », ou une expression cron à 5 champs, dans le fuseau du navigateur), et l'IA l'exécute seule en arrière-plan. Preset épinglé par tâche (bascule de modèle avant l'exécution, attente du rechargement), accès mémoire et web réglables, interrupteur maître pour tout suspendre, bouton « tester maintenant ». Le planificateur est une goroutine, un tic par minute, dans le process qui détient la conversation et parle au moteur. Une seule tâche part par tic : de toute façon une seule inférence tourne à la fois, et étaler les départs évite qu'une rafale monopolise le modèle. Occupé ou modèle en cours de chargement n'est pas un échec — la tâche repasse au tic suivant. Une tâche ne partage QU'UN point avec le chat : le verrou de génération. Ni messages, ni journal d'affichage, ni epoch — elle construit son fil éphémère et le jette, ne gardant que son texte final comme compte-rendu (borné à 4000 caractères, réinjecté au passage suivant pour la continuité). Deux adaptations, parce que loki n'est pas l'amont : — Dossier de travail. Ici il appartient à la DISCUSSION ouverte : une tâche y aurait déposé ses fichiers, et en aurait changé en cours de route si l'utilisateur changeait de discussion — pour disparaître avec elle à la suppression. Chaque tâche a donc le sien (workspace/tasks/<id>/), stable d'un passage à l'autre. La bascule ne touche que les points d'entrée des OUTILS (agentCwd) : le panneau Fichiers, les dépôts et les liens des messages continuent de suivre la discussion de l'utilisateur. — Capacités. Mem est posé explicitement à MemOff quand l'agent est coupé : le zéro de MemMode est la chaîne vide, qu'EnabledTools ne reconnaît pas comme « coupée » — une tâche sans agent se serait vu offrir les outils mem_*. Le mode code reste off : rôles, critères et passe de vérification n'ont pas de sens sans personne en face. Le refus d'un message pendant qu'une tâche tourne dit maintenant LAQUELLE occupe le modèle : « génération en cours » sur un fil vide et immobile n'expliquait rien. Interface : section repliable dans les réglages (liste, état, prochain passage, pastille), modale d'édition bâtie sur le gabarit de l'éditeur de preset, panneau « dernier résultat » en markdown. Vérifié dans un vrai navigateur — création, rendu, réouverture en édition, bascule intervalle/cron, interrupteur maître, suppression — sans une seule erreur JS. |
||
|
|
0a3af60715 |
Intensité du raisonnement dans la barre de saisie, angles moins arrondis
Le niveau de raisonnement n'existait que dans l'éditeur de preset : le changer demandait d'ouvrir les réglages, éditer, enregistrer. Or ça se décide au moment d'écrire le message. - Nouvelle route /api/reasoning-effort (GET/POST), calquée sur /api/memory : elle écrit REASONING_EFFORT dans la config vivante, relue à chaque requête au moteur. Aucun redémarrage — la valeur voyage dans le corps de la requête. - Liste blanche côté serveur : cette clé finit dans une requête au moteur, on n'y laisse pas passer une chaîne arbitraire venue du navigateur. - La liste est grisée quand le raisonnement est coupé pour ce modèle, plutôt que masquée : le réglage reste trouvable, et l'infobulle dit où le rallumer. - L'éditeur de preset garde le même réglage comme DÉFAUT du modèle. Appliquer un preset réécrit toute la config, donc il reprend la main sur le choix fait à la volée — les deux sous-titres le disent, sinon la double présence intrigue. Angles : les rayons allaient de 5 à 26px selon les composants, ce qui donnait des cartes très rondes. Tout est ramené à 4px (cartes, boutons, modales) et 3px (petits éléments), y compris les formes multi-valeurs comme la barre de saisie (26px 26px 0 0 → 3px 3px 0 0). Les pastilles (999px) et les ronds (50%) sont laissés intacts : ce sont des interrupteurs et des avatars, pas des cartes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b518e98b43 |
Accès OpenAI : servi par Loki, par domaine ou par IP
L'endpoint compatible OpenAI n'était pas servi par Loki : le panneau annonçait l'adresse de llama-server lui-même, http://<ip>:8080/v1. Dans le déploiement de référence de ce fork, cette adresse ne peut joindre personne — le port 8080 n'est pas publié par le conteneur, l'entrypoint sème HOST=127.0.0.1, et l'IP annoncée est celle du bridge Docker. L'autre voie proposée, « exposer en public (ajean.link) », exigeait un jeton de relais que ce fork ne permet plus d'obtenir : l'interrupteur ne pouvait que renvoyer vers un panneau supprimé. Désormais, Loki sert /v1/* SUR SON PROPRE PORT et relaie vers le moteur. L'API est donc joignable partout où l'interface l'est — IP du réseau local, nom de domaine, reverse proxy — sans publier de second port ni ouvrir le moteur. Serveur - mountOAI (llm_oai.go) monte /v1/ sur le mux, et RIEN d'autre : ni /metrics, ni /props, ni /slots, qui divulgueraient le modèle chargé et l'état des slots. Le filtre interne d'oaiHandler reste en seconde barrière. - requireCompletionKey (web_auth.go) garde cette surface avec la clé des COMPLÉTIONS, pas celle de pilotage : un client OpenAI n'a qu'un en-tête Authorization, et on veut pouvoir lui donner l'accès au modèle sans le droit de redémarrer la machine. Erreurs au format d'OpenAI (body.error.message), que les SDK savent présenter. Le préflight CORS passe sans clé — il n'en porte jamais, et le refuser casserait tout client tiers de navigateur. - effectiveAPIKeyErr (backend_config.go) devient la source unique de la clé exigée : base d'abord, config.env en repli, exactement comme le moteur. Sans ce miroir, un API_KEY résiduel donnait un endpoint « ouvert » côté Loki et un 401 côté moteur, sans rien pour l'expliquer. Lecture ratée = refus, jamais ouverture (même raisonnement que readWebKeyErr). - oaiHandler passe à ReverseProxy.Rewrite : le port du moteur est relu à chaque requête au lieu d'être figé à la construction — il visait l'ancien port dès qu'on changeait PORT, jusqu'au redémarrage de Loki. - withLocalAuth (relay_link.go) n'injecte plus la clé de pilotage sur /v1 : elle aurait été refusée par la garde, et surtout relayée au moteur. Le trafic du tunnel est marqué (en-tête effacé avant d'être posé, sinon un client le forge) et la surface y reste fermée tant que oai_public est faux — la promesse du tunnel est tenue. Adresse affichée - web_public_url.go : normalisation d'une adresse publique saisie à la main (schéma ajouté, /v1 recopié toléré, chemin refusé), origine de la requête via Host + X-Forwarded-Proto, et la règle de priorité entre les deux. - Le calcul quitte le navigateur pour le serveur : c'est la concaténation côté client qui produisait l'adresse fantôme. Interface - Le panneau perd l'interrupteur ajean.link et l'interrupteur d'écoute LAN — ce dernier n'a plus d'objet, et deux interrupteurs pour « rendre l'IA joignable » était la confusion à lever. La route /api/network et `loki network` restent pour qui veut exposer le moteur en direct. - Il gagne un champ « adresse publique » (facultatif, pour le reverse proxy) et un avertissement rouge tant qu'aucune clé n'est définie — l'endpoint est maintenant ouvert PARTOUT où l'interface l'est, ça ne se dit pas à voix basse. Le démarrage de `loki web` le crie aussi. Vérifié bout en bout sur le serveur réel : liste des modèles à travers Loki avec la clé (200), sans la clé (401), et complétion en streaming dont les tokens arrivent espacés de 120 ms — le flux traverse bien le double proxy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LPyFxVHNAN9u5pVzSYMwjd |
||
|
|
f99e5b59b8 |
Refonte de l'interface : direction « Sober Tech »
Reprise du design d'après la maquette fournie, sans changer d'architecture : l'UI reste du HTML/CSS/JS assemblé dans le binaire (voir plus bas). Charte - Palette ardoise + sauge en remplacement des bruns « Terre ». Deux variantes : claire par défaut (celle de la maquette) et « Deep Dark » (fond #0F172A, cartes #1E293B), à un clic depuis l'en-tête. Une variable --on-accent porte ce qui s'écrit sur les aplats de sauge, pour que le contraste tienne dans les deux variantes. - Typographie Inter (interface) + JetBrains Mono (code, chiffres, chemins), en sous-ensemble latin, embarquées comme l'étaient Bricolage et IBM Plex Mono — toujours aucune requête vers un service de polices. - Boutons sans contour, fond au survol, léger enfoncement au clic. - Coque à plat : plus de cartes flottantes séparées par une gouttière, la barre latérale est collée au bord et le fil occupe tout le reste. Coque - Barre d'en-tête : titre de la discussion + sélecteur de modèle. Changer de preset demandait d'ouvrir la barre latérale et de descendre jusqu'aux presets ; c'est désormais une liste déroulante, toujours visible. - Barre latérale en trois zones — marque, contenu défilant, moniteur machine — et escamotable d'un clic sur grand écran. Les discussions y passent au premier plan, avec une recherche textuelle (filtrage côté client : la liste est déjà chargée, sans les messages) ; les réglages descendent sous un repli unique, d'où openDetails(), qui déplie aussi les parents. - Moniteur machine en pied de colonne : une jauge par ressource (charge GPU, puis VRAM et température en détail, mémoire vive), sauge jusqu'à 75 %, ambre puis rouille quand la machine sature. Il remplace la section « Machine », qui disait la même chose en plus verbeux et en plus loin. - L'option « barre latérale escamotable » disparaît d'Apparence : elle faisait de la barre un tiroir posé SUR la conversation, là où le bouton d'en-tête l'escamote pour de bon. Deux mécanismes concurrents pour la même intention. Fil et saisie - La réponse de l'IA redevient une carte, la question un aplat de sauge : sur un fond de fil coloré, du texte nu flottait sans ancrage. - Saisie en pilule, ses outils (joindre, fichiers, envoyer) dans la barre elle-même. L'envoi est une pastille ronde à flèche ; le mot « Envoyer » reste porté par aria-label et l'infobulle. Corrections croisées - L'heure d'une discussion prenait la moitié de la ligne (flex:1 hérité de `.preset>span`), le titre était tronqué au premier mot. - Une liste déroulante posée directement dans une ligne de modale débordait sous son intitulé quand sa valeur était longue (chemin de destination). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LPyFxVHNAN9u5pVzSYMwjd |
||
|
|
133b30421a |
Postes distants : retirer le bouton oublié du composeur
Le retrait de l'accès distant s'était arrêté à mi-chemin. La section « Accès distant » de la barre latérale et son module 13-remote.js ont bien disparu au commit |
||
|
|
3740b881a8 |
Hauteur : bulles techniques en rangée, sections groupées, accès distant retiré
Trois gains de place, mesurés au navigateur en 1500×900. - Raisonnement, outils et mémoire se posent CÔTE À CÔTE dans une rangée qui déborde à la ligne : un tour d'agent en enchaîne parfois dix, et empilées elles repoussaient la réponse hors de l'écran alors qu'elles ne portent qu'une étiquette tant qu'elles sont repliées. Mesuré : 8 bulles occupent 2 lignes au lieu de 8. Dépliée, une bulle reprend toute la largeur — son contenu ne doit pas être comprimé dans une colonne étroite. - Les sections de la barre latérale sont réunies en DEUX cartes (réglages d'IA / réglages d'application) au lieu d'une carte chacune : onze arrondis et autant de gouttières faisaient déborder la colonne. Mesuré : 876 px de contenu pour 876 px visibles — plus d'ascenseur. - Section « Accès distant » supprimée, ainsi que son module JS (13-remote.js) et son chargement : elle pilotait le tunnel ajean.link, sans objet ici. Le code serveur du relais reste en place mais inerte (aucun jeton) : le retirer créerait des conflits à chaque reprise de l'amont. |
||
|
|
54c5eb1334 |
Identité dans le chat, section Paramètres, logo agrandi
- Identité : prénom et avatars (emoji) affichés en tête des bulles, à la place des libellés « user » / « assistant ». Stockés dans les préférences SERVEUR, donc partagés entre appareils comme le thème. La liste d'emojis est servie par /api/prefs : pas de seconde copie côté client. Validation stricte — prénom nettoyé de ses caractères de contrôle et borné à 24 runes, avatar refusé s'il n'est pas dans la liste fermée. - Barre latérale : séparateur « Paramètres » qui regroupe Identité, Apparence, Accès OpenAI, Accès distant et Actions, sous les réglages d'IA (Machine, Presets, Mode agent, System prompt, Moteur). Un séparateur plutôt qu'un second niveau de repli, illisible dans une colonne aussi étroite. - Logo : 10 → 17 px, il était minuscule sur un écran dense. Le prénom vient de l'utilisateur : les libellés sont écrits en textContent, jamais en innerHTML. |
||
|
|
2fbf86cdde |
Historique : plusieurs discussions, et mise à jour par l'image en conteneur
L'amont ne connaît qu'un fil unique (bkChat/conversation) que « clear chat »
effaçait définitivement. On garde toute la machinerie (un seul conv en
mémoire, mêmes flux SSE, même compactage) mais rangée par discussion :
bkChat/index liste des discussions (métadonnées seules)
bkChat/active discussion ouverte, partagée par tous les appareils
bkChat/conv:<id> état complet d'une discussion
Basculer réutilise le mécanisme d'epoch du reset : les abonnés SSE reçoivent
{reset:true} et rejouent le nouveau fil — aucun code de rendu à toucher. Le
fil unique existant est repris comme première discussion au premier
démarrage, et sa clé d'origine est laissée intacte.
- routes /api/conversations (liste, new, switch, rename, delete)
- barre latérale : liste (titre déduit du 1er message, date, nb d'échanges),
bouton +, renommer, supprimer ; lignes construites en DOM et non en
innerHTML, les titres venant de messages utilisateur
- suppression de la dernière discussion : convCreate et non convNew, qui
aurait réenregistré celle qu'on vient d'effacer
Le bouton « Vérifier les mises à jour » répondait « GitHub a répondu 404 » :
il interrogeait les releases du dépôt du fork, qui n'en publie aucune. En
conteneur, remplacer le binaire n'a de toute façon pas de sens — l'UI, l'API
et la CLI renvoient désormais « docker compose pull ».
Vérifié en conteneur : création, bascule, renommage (titre accentué avec
< > &), suppression de l'active puis de la dernière ; /api/update et
loki update renvoient la note Docker.
|
||
|
|
de6551a153 |
Rebaptise AJEAN en Loki (fork, lignée conservée)
- module github.com/R0m1k3/Loki, cmd/loki, internal/loki (package loki) - LOKI_HOME, LOKI_MODEL_DIRS, LOKI_SERVICE, LOKI_DL_CONNS ; /etc/loki ; units loki-engine / loki-ui ; binaire et aide CLI - updateRepo pointe sur R0m1k3/Loki (l'auto-update ne tirera plus les binaires AJEAN amont) Conservé à l'identique : le domaine ajean.link (service de tunnel amont), les littéraux de migration 0.7.x (migrate_07.go), RELEASE_NOTES.md et LICENSE (historique et licence de l'amont). go build/vet/test : verts. |