mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-21 14:08:11 +02:00
Fil long : retour au replay complet avant la reprise du fenêtrage par échanges
Annule c32fd40. Le replay borné aux 4000 derniers événements coupait au
milieu d'un tour, perdait l'état du mode Code (critères, jauge de contexte)
porté par la partie masquée et s'imposait à tous les clients. Le fenêtrage
par échanges repris d'AJEAN (commit suivant) coupe aux frontières d'échange
et renvoie cet état en tête.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
04137411fa
commit
51c791268d
8 files changed
+11
-182
No files matched your search
@@ -4,10 +4,6 @@
|
||||
// suit le direct. Fermer l'onglet n'arrête plus la génération (détachée côté
|
||||
// serveur) ; se reconnecter rejoue tout le fil, détails compris.
|
||||
let lastSeq=0, streamAbort=null;
|
||||
// REPLAY_FULL : demander le journal ENTIER au prochain abonnement. Le serveur
|
||||
// ne rejoue par défaut que la fin d'une longue discussion (voir replayTailMax) ;
|
||||
// le bandeau « charger le début » rouvre le flux avec ce drapeau.
|
||||
let REPLAY_FULL=false;
|
||||
// Bulle « en attente » : affichée EN GRIS dès l'appui sur envoyer, avant tout
|
||||
// aller-retour réseau. Le message ne disparaît donc plus de l'écran entre la
|
||||
// frappe et la réponse du serveur. Elle s'éclaircit (classe retirée) quand
|
||||
@@ -407,44 +403,10 @@ function feedBlock(el, full){ if(REPLAYING) scheduleRender(el, full); else smoot
|
||||
// bulle d'outil) doit voir le texte complet.
|
||||
function settleBlocks(){ smoothSnap(); flushRender(); }
|
||||
|
||||
// showReplayBanner affiche, en tête du fil, le bandeau « début masqué ». Un clic
|
||||
// coupe le flux et se réabonne depuis zéro en demandant TOUT le journal.
|
||||
function showReplayBanner(hidden){
|
||||
const c=chatEl(); if(!c) return;
|
||||
let b=document.getElementById('replay-banner');
|
||||
if(!b){
|
||||
b=document.createElement('div');
|
||||
b.id='replay-banner'; b.className='replay-banner';
|
||||
c.insertBefore(b, c.firstChild);
|
||||
}
|
||||
b.textContent='';
|
||||
const txt=document.createElement('span');
|
||||
txt.textContent='Début de la discussion masqué ('+hidden+' événements) — ';
|
||||
const btn=document.createElement('button');
|
||||
btn.type='button'; btn.className='replay-more'; btn.textContent='charger le début';
|
||||
btn.onclick=()=>{ btn.disabled=true; btn.textContent='chargement…'; loadFullReplay(); };
|
||||
b.appendChild(txt); b.appendChild(btn);
|
||||
}
|
||||
|
||||
// loadFullReplay relance l'abonnement depuis le début, journal entier. On repart
|
||||
// d'un fil VIDE : rejouer par-dessus l'existant ferait doublon.
|
||||
function loadFullReplay(){
|
||||
REPLAY_FULL=true; lastSeq=0; REPLAYING=true;
|
||||
if(streamAbort) streamAbort.abort();
|
||||
const c=chatEl(); if(c){ c.innerHTML=''; c.style.opacity='0'; }
|
||||
PENDING=null; newTurn();
|
||||
setChatLoading('chargement du début de la conversation…');
|
||||
connectStream();
|
||||
}
|
||||
|
||||
// Traite UN événement du flux — même sémantique que l'ancien switch inline, mais
|
||||
// piloté par le serveur et rejouable à l'identique.
|
||||
function handleDelta(d){
|
||||
if(typeof d.seq==='number' && d.seq>lastSeq) lastSeq=d.seq;
|
||||
// Replay borné : le serveur a sauté le début d'une longue discussion. On
|
||||
// l'annonce en tête du fil, avec le bouton qui va le chercher. Rien n'est
|
||||
// perdu : le journal complet est sur le disque.
|
||||
if(typeof d.replay_truncated==='number'){ showReplayBanner(d.replay_truncated); return; }
|
||||
// Recalage de l'horloge : un événement reçu en DIRECT vient d'être émis, son
|
||||
// `ts` serveur et l'heure locale désignent donc le même instant. Surtout pas
|
||||
// pendant le rejeu, où les `ts` sont vieux de plusieurs heures.
|
||||
@@ -595,7 +557,7 @@ async function connectStream(){
|
||||
while(document.hidden){ await new Promise(res=>setTimeout(res, 500)); }
|
||||
streamAbort=new AbortController();
|
||||
try{
|
||||
const r=await jfetch('/api/chat',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({from:lastSeq, full:REPLAY_FULL}),signal:streamAbort.signal});
|
||||
const r=await jfetch('/api/chat',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({from:lastSeq}),signal:streamAbort.signal});
|
||||
if(REPLAYING) setChatLoading('chargement de la conversation…');
|
||||
const reader=r.body.getReader(); const dec=new TextDecoder(); let buf='';
|
||||
while(true){
|
||||
|
||||
@@ -443,13 +443,6 @@ button:disabled{opacity:.5;cursor:not-allowed}
|
||||
.diff-count{margin-left:8px;letter-spacing:0;text-transform:none}
|
||||
.diff-count .a{color:var(--add)}
|
||||
.diff-count .d{color:var(--del)}
|
||||
/* Bandeau « début de la discussion masqué » : le serveur ne rejoue que la fin
|
||||
d'un très long fil (replayTailMax). Discret, en tête du fil, avec le bouton
|
||||
qui va chercher le reste. */
|
||||
.replay-banner{margin:4px auto 10px;padding:6px 10px;font-size:11px;color:var(--dim);background:var(--panel);border:1px solid var(--border);border-radius:3px;text-align:center;max-width:680px}
|
||||
.replay-banner .replay-more{padding:2px 8px;font-size:11px;background:none;border:1px solid var(--border);color:var(--dim);border-radius:3px;cursor:pointer}
|
||||
.replay-banner .replay-more:hover{color:var(--accent);border-color:var(--accent)}
|
||||
.replay-banner .replay-more:disabled{cursor:default;opacity:.6}
|
||||
.msg.tool .tool-sub{font-size:10px;color:var(--dim);text-transform:uppercase;letter-spacing:.1em;margin:8px 0 4px}
|
||||
/* Résultat d'outil tronqué : « voir plus » et « copier » réunis dans une barre
|
||||
ancrée en bas à droite, au lieu d'une ligne séparée sous le bloc. Le pre
|
||||
|
||||
Reference in new issue
Block a user