UI : anneau d'activité dans la liste des discussions, temps de travail sous les réponses

Deux manques dans la présentation d'un tour :

1. Rien ne disait sur QUELLE discussion un agent était en train de
   travailler. La ligne concernée porte maintenant un anneau qui tourne,
   à gauche du titre — et l'en-tête aussi, puisque la barre latérale est
   escamotée sur téléphone. L'état vient de deux sources : le flux SSE
   (instantané) et /api/conversations, qui expose désormais `busy` pour
   que la page ouverte en cours de génération s'anime sans attendre le
   rejeu du journal. L'indicateur est posé et retiré SANS redessiner la
   liste : un redessin relancerait l'animation à chaque événement.

2. Le pied des réponses ne montrait que la vitesse du moteur, jamais le
   temps que le tour avait pris. Il porte maintenant « travail 1 min 04 s »
   — de la question envoyée à la fin du tour, raisonnement, appels
   d'outils et attentes compris. La durée avance à la seconde pendant le
   tour et se fige au turn_done ; elle apparaît aussi sur l'indicateur
   « … », là où il n'y a pas encore de réponse sous laquelle écrire.
   La bulle de raisonnement gagne au passage sa propre durée.

La mesure est prise sur les HORODATAGES SERVEUR (événements `user` et
`turn_done`) : elle est donc juste en direct comme au rejeu, où tout
arrive d'un bloc côté client. Le compteur vivant se recale sur l'écart
entre l'horloge du navigateur et celle du serveur, réévalué à chaque
événement reçu en direct — un téléphone n'est pas à la même heure que la
machine.

« Masquer la vitesse de génération » ne masque plus que la vitesse : la
durée n'est pas une mesure de moteur, c'est ce que la réponse a coûté.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5UndZ9DedRXPuAoRXbmDb
This commit is contained in:
Claude committed 2026-08-18 08:35:51 +00:00
1 parent 88e1b38582
commit 3d8a72754c
9 files changed
+488 -35

No files matched your search

+5 -1
View File
@@ -130,7 +130,11 @@ func handleConvList(w http.ResponseWriter, r *http.Request) {
if list == nil {
list = []convMeta{}
}
sendJSON(w, 200, map[string]any{"conversations": list, "active": active})
// `busy` = un tour est en cours SUR LA DISCUSSION ACTIVE (il n'y a qu'une
// génération à la fois, sur le fil ouvert). L'UI s'en sert pour animer la
// ligne concernée dès le chargement, avant même que le flux SSE ait rejoué
// le journal — sinon la page reste muette pendant qu'un agent travaille.
sendJSON(w, 200, map[string]any{"conversations": list, "active": active, "busy": conv.isGenerating()})
}
func handleConvNew(w http.ResponseWriter, r *http.Request) {