dev-tourBUG-006RESOLVED

Sherlock comportement

Créé 24/05/2026 14:04:58 · MAJ 24/05/2026 14:25:00 · 2 images

001-img-4009.png

002-img-4010.png

Diagnostic

Les screenshots révèlent 3 sous-bugs distincts sur la POC Sherlock+Claude Agent livrée 2026-05-24 :

1. Markdown brut (raw **bold**) — bloquant lisibilité

Dans la 1ère bulle assistant, on voit littéralement **Quand je clique sur 'Commander'**, **ce que tu fais**, **ce qui se passe**, **BUG-XXX** — les astérisques de bold markdown ne sont pas rendues parce que BubbleView (composants/sherlock/sherlock-chat.tsx:300) affiche le texte assistant en whitespace-pre-wrap brut.

react-markdown est déjà dans les deps (^10.1.0) mais pas utilisé. Fix trivial.

2. Sherlock répond en boilerplate au lieu d'utiliser ses tools

Sur "Test pour voir les bugs", Sherlock ne tente pas une seule fois d'appeler Glob/Read/Bash sur le tracker. Il répond avec une politesse générique listant des exemples ("Quand je clique sur 'Commander' en mobile, ça freeze", "Login KO sur iOS depuis le build 7", etc.) et redemande au user de reformuler. Le 2nd turn fait pareil : il liste 2 options ("décris un bug" / "lance /triage-bugs") mais ne lance rien lui-même.

Cause racine : le system prompt (app/api/sherlock/route.ts:24-50) dit littéralement « pose une question de clarification si vraiment ambigu, sinon plonge directement » — Claude joue prudent et privilégie la clarif. Il faut inverser : « plonge toujours en premier, demande clarification seulement après avoir essayé ».

3. Footer "SESSION TERMINÉE" trompeur

Quand le turn assistant finit, le footer affiche en gros "SESSION TERMINÉE · 1 TURN · 9.7s · $0.1395". L'user lit ça comme "le chat s'est fermé, je dois recommencer" alors qu'en réalité la zone de saisie en bas reste active et le sessionId est gardé pour la reprise.

Fix : remplacer "Session terminée / Session interrompue" par un wording qui dit explicitement « le tour est fini, continue à poser des questions ».

Bonus demandé par user

Pendant le bug logging, le user demande aussi l'upload d'images dans le chat (captures d'écran). Pas un bug à proprement parler, ajouté en parallèle des 3 fixes.

Fix

#1 — Markdown rendu (components/sherlock/sherlock-chat.tsx:357-361)

Remplacé <div className="whitespace-pre-wrap break-words">{bubble.text}</div> par un <ReactMarkdown remarkPlugins={[remarkGfm]}>{bubble.text}</ReactMarkdown> enveloppé dans un wrapper prose prose-sm dark:prose-invert avec resserrage des espacements (prose-p:my-1 prose-ul:my-1 prose-pre:my-2) pour rester compact dans une bulle de chat. react-markdown + remark-gfm étaient déjà dans les deps — zéro install.

#2 — System prompt action-oriented (app/api/sherlock/route.ts:25-50)

Réécrit la section méthodologie. Ajout d'une « Règle d'or : PLONGE TOUJOURS EN PREMIER » explicite avec 3 cas concrets :

  • Message vague type "test" → liste le tracker ou les fichiers récents.
  • Message court qui mentionne une zone → grep cette zone direct.
  • Capture d'écran seule → décris ce que tu vois et propose des hypothèses.

Et : « Pose une question de clarification SEULEMENT après avoir tenté au moins une action ». La consigne inverse de l'ancienne version qui tolérait les clarifs en premier.

#3 — Footer wording (components/sherlock/sherlock-chat.tsx:419)

"Session terminée""Tour terminé — continue à poser des questions ↓" (avec la flèche pointant vers le composer toujours actif). "Session interrompue""Tour interrompu". Le mot « session » était trompeur car il évoquait la fin du chat alors que le sessionId reste utilisable. « Tour » = ce qu'Anthropic appelle un "turn" du modèle.

Bonus — Upload d'images

  • Helper lib/image-attach.ts : validation (png/jpeg/gif/webp, 5 MB max, 4 images max par turn), lecture base64 via FileReader, payload propre.
  • Backend app/api/sherlock/route.ts :
    • Body étendu avec images?: Array<{ mediaType, base64 }>.
    • Validation côté serveur (media type + taille).
    • Quand images présentes : buildMultimodalPrompt() crée un AsyncGenerator<SDKUserMessage> qui yield un seul message user avec content blocks Anthropic ({ type: "image", source: { type: "base64", media_type, data } } + { type: "text", text: symptom }). Le SDK accepte prompt: AsyncIterable<SDKUserMessage> pour ça.
    • Ajout de q.close() dans un finally après le streaming, pour fermer proprement le subprocess quand on a passé un async iterable (sinon le tour reste ouvert côté SDK).
  • Frontend :
    • components/sherlock/sherlock-chat.tsx : bouton 📎 dans le composer, drag-drop sur toute la zone chat (overlay bleu pendant le drag), preview thumbs au-dessus du composer avec bouton × hover, accepte initialImages prop pour démarrer avec des images.
    • components/sherlock/sherlock-search.tsx : même bouton 📎 + preview dans la form d'enquête (permet d'attacher dès le premier symptôme). Si des images sont jointes, le tier 1 règles statiques est court-circuité → Claude direct.
  • Bulle user mise à jour pour afficher les thumbs au-dessus du texte.

Vérifications

  1. Markdown rendering — smoke test via curl SSE avec prompt "affiche **Hello** en gros…" → Claude répond bien **Hello**\n\n- file1\n- file2 et ReactMarkdown rendra ça en <strong>Hello</strong> + liste à puces. Reste à valider visuellement via la UI une fois le serveur réparé.
  2. System prompt — relancer un symptôme vague type "test pour voir les bugs" devrait maintenant déclencher un Glob sur /home/debian/superApp_V1/bugs/ au lieu d'une réponse boilerplate. À valider visuellement par le user.
  3. Footer wording — ne se vérifie qu'à l'œil dans la UI.
  4. Upload image — testé end-to-end : payload base64 de 1 MB (le screenshot BUG-006 lui-même) transmis au SDK, Claude a correctement lu l'image et même diagnostiqué le bug visible dans le screenshot ("l'utilisateur a envoyé 'Test pour voir les bugs' (deux fois)…"). La vision Anthropic fonctionne via l'auth Max OAuth.

Caveat — état du repo dev-tour

Le test UI complet est bloqué par un état préexistant et non-lié à Sherlock : app/page.tsx importe @/components/home/home-switch mais ce fichier a été supprimé (avec d'autres components/home/*.tsx et components/mode/*.tsx) en local sans que le commit soit fait. Conséquence : la home / renvoie 500 et bloque le test visuel du chat. À toi de gérer cette WIP (soit git restore les fichiers supprimés, soit fixer/supprimer l'import dans page.tsx). /sherlock et /api/sherlock répondent correctement, eux.

Files touched

  • app/api/sherlock/route.ts (system prompt + body images + buildMultimodalPrompt + q.close)
  • components/sherlock/sherlock-chat.tsx (markdown + footer + composer attach + drag-drop + bulle user images)
  • components/sherlock/sherlock-search.tsx (form attach + thumbs + pass through initialImages)
  • lib/image-attach.ts (nouveau — helpers validation + base64)

Chemin disque : /home/debian/superApp_V1/bugs/dev-tour/BUG-006-sherlock-comportement/