From 4e5bc44607fe7ae6a4f8d60e00d09a4a1b3bf580 Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Wed, 19 Aug 2026 08:11:38 +0200 Subject: [PATCH] =?UTF-8?q?Captures=20d'=C3=A9cran=20:=20montr=C3=A9es=20d?= =?UTF-8?q?ans=20la=20bulle,=20sans=20d=C3=A9pendre=20du=20mod=C3=A8le?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La capture n'apparaissait dans le fil QUE si le modèle recopiait la ligne markdown rendue par l'outil. Un petit modèle l'oublie, et l'utilisateur ne voyait jamais l'image qu'il avait demandée — la capture existait pourtant bien sur le disque. L'événement d'outil porte désormais le chemin de l'image et l'interface la rend directement dans la bulle web_screenshot (cliquable pour la loupe, comme les autres images du fil). Ce que le modèle en écrit ensuite reste possible, mais n'est plus la condition de l'affichage. Co-Authored-By: Claude Opus 5 --- internal/loki/chat_conversation.go | 3 +++ internal/loki/code_verify.go | 3 +++ internal/loki/llm_client.go | 14 +++++++++++++- internal/loki/ui/index.html | 20 ++++++++++++++++++++ internal/loki/ui/src/js/08-chat-render.js | 15 +++++++++++++++ internal/loki/ui/src/styles.css | 5 +++++ 6 files changed, 59 insertions(+), 1 deletion(-) diff --git a/internal/loki/chat_conversation.go b/internal/loki/chat_conversation.go index a20119f..5260d3c 100644 --- a/internal/loki/chat_conversation.go +++ b/internal/loki/chat_conversation.go @@ -442,6 +442,9 @@ func (c *Conversation) generate(ctx context.Context, caps Caps, temperature floa if len(ev.ToolUsed.Diff) > 0 { tu["diff"] = ev.ToolUsed.Diff } + if ev.ToolUsed.Image != "" { + tu["image"] = ev.ToolUsed.Image + } c.appendDelta(epoch, map[string]any{"tool_used": tu}) case ev.NewHistory != nil: // Compaction faite en cours de tour : elle remplace la base au lieu de diff --git a/internal/loki/code_verify.go b/internal/loki/code_verify.go index ce1e94f..799b8fe 100644 --- a/internal/loki/code_verify.go +++ b/internal/loki/code_verify.go @@ -155,6 +155,9 @@ func (c *Conversation) forwardStream(ev StreamEvent, epoch int) { if len(ev.ToolUsed.Diff) > 0 { tu["diff"] = ev.ToolUsed.Diff } + if ev.ToolUsed.Image != "" { + tu["image"] = ev.ToolUsed.Image + } c.appendDelta(epoch, map[string]any{"tool_used": tu}) case ev.Ask != nil: c.appendDelta(epoch, map[string]any{"ask": ev.Ask}) diff --git a/internal/loki/llm_client.go b/internal/loki/llm_client.go index 38b99e3..484bc6f 100644 --- a/internal/loki/llm_client.go +++ b/internal/loki/llm_client.go @@ -370,6 +370,12 @@ type ToolUsedEvent struct { // Diff : lignes ajoutées/retirées quand l'outil a MODIFIÉ quelque chose // (edit, mem_add, mem_edit). L'UI les affiche en vert (+) et rouge (-). Diff []DiffLine + // Image : chemin (relatif au dossier de travail) d'une image PRODUITE par + // l'outil — aujourd'hui la capture de web_screenshot. L'UI l'affiche dans la + // bulle de l'outil. Sans ça, la capture n'apparaissait QUE si le modèle + // pensait à recopier la ligne markdown rendue par l'outil : un petit modèle + // l'oublie, et l'utilisateur ne voyait jamais l'image qu'il avait demandée. + Image string } // shownDisplayMax borne ce qu'un résultat d'outil occupe dans le FLUX vers l'UI. @@ -1210,7 +1216,13 @@ func runChat(ctx context.Context, messages []Message, temperature float64, caps if !strings.HasPrefix(result, "[erreur]") { doneCalls[callKey] = result } - cb(StreamEvent{ToolUsed: &ToolUsedEvent{Name: tc.Function.Name, Label: label, Result: shownResult(result), Done: true, Diff: diff}}) + // Capture d'écran : l'image part avec l'événement pour être + // affichée dans la bulle, quoi que le modèle en fasse ensuite. + shot := "" + if tc.Function.Name == "web_screenshot" { + shot = capturedRelPath(result) + } + cb(StreamEvent{ToolUsed: &ToolUsedEvent{Name: tc.Function.Name, Label: label, Result: shownResult(result), Done: true, Diff: diff, Image: shot}}) toolMsg := Message{Role: "tool", ToolCallID: tc.ID, Content: result} messages = append(messages, toolMsg) extra = append(extra, toolMsg) diff --git a/internal/loki/ui/index.html b/internal/loki/ui/index.html index d8b6dad..57ea365 100644 --- a/internal/loki/ui/index.html +++ b/internal/loki/ui/index.html @@ -2026,6 +2026,11 @@ html[data-files="1"] #files-btn{color:var(--accent)} .askopts button{border:1px solid var(--accent);background:transparent;color:var(--accent);border-radius:3px;padding:4px 10px;font-size:13px;cursor:pointer;font-family:inherit} .askopts button:hover:not(:disabled){background:var(--accent-bg)} .askopts button:disabled{opacity:.5;cursor:default} + +/* Capture d'écran rendue dans la bulle de l'outil (web_screenshot) : l'image + ne dépend plus du modèle qui pense — ou non — à la recopier dans sa réponse. */ +.tool-shot{margin-top:8px} +.tool-shot img{max-width:100%;max-height:420px;border:1px solid var(--border);border-radius:4px;display:block;cursor:zoom-in}