--- issueRef: "#157" version: 19 updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"} updatedAt: 1786380032724 --- # Journal d'itération (le plus récent en haut) ## Itération 4 — 2026-08-10 — Correctif livré, QA verte ciblée, merge local sur `develop`, attente de validation AppImage live ### Diagnostic final du cycle Le problème utilisateur n'était **pas** uniquement frontend. - **Backend Codex** : un `agent_message` d'intention avant `idea_ask_agent` pouvait être traité comme faux candidat `Final` et ne pas être projeté live. De plus, le parser/session Codex émettait à la fois un `Progress` canonique et un `ToolActivity` de compatibilité pour certains événements tool/MCP (`conversation.item.added` / `conversation.item.done`), ce qui créait déjà une duplication en amont de l'UI. - **Frontend custom CLI** : la réconciliation des cartes de progress ne dédupliquait pas au niveau de l'entité visuelle métier. Le même `idea_ask_agent` pouvait donc produire deux cartes distinctes (`Provider tool` puis `Délégation`) au lieu d'une seule carte `start` et d'une seule carte `done`. ### Correctifs réalisés #### Backend (`#171` transverse, impact direct sur `#157`) - Reclassification d'un `agent_message` pré-MCP en `Announcement` dès qu'un événement ultérieur prouve que le tour continue, au lieu de l'avaler comme candidat `Final`. - Suppression de l'émission doublon `ToolActivity` quand un `ReplyEvent::Progress` canonique existe déjà pour l'événement Codex/MCP concerné. - Fichiers: `crates/infrastructure/src/session/codex.rs`, `crates/infrastructure/src/session/mod.rs`. #### Frontend (`#157`) - Déduplication par entité visuelle métier: même délégation/tool + même bucket `started` ou `completed` = une seule carte. - `idea_ask_agent` / `idea_ask_agents` toujours rendus comme **délégation**, même si le provider les remonte comme `providerNative/tool`. - Le `Final` ne crée pas une deuxième carte `done`; il termine simplement l'état en cours quand approprié. - Fichiers: `frontend/src/features/agents/CustomAgentChatView.tsx`, `frontend/src/features/agents/CustomAgentChatView.test.tsx`. ### Preuves de test / QA QA a rejoué et validé les commandes suivantes: - `CARGO_HOME=/tmp/idea-cargo-home cargo test -p infrastructure codex -- --nocapture` → **41 passed** - `CARGO_HOME=/tmp/idea-cargo-home cargo test -p app-tauri --test chat_bridge -- --nocapture` → **25 passed** - `cd frontend && npx vitest run src/features/agents/CustomAgentChatView.test.tsx` → **26 passed tests** - `cd frontend && npx vitest run` → **1133 passed tests** - `cd frontend && ./node_modules/.bin/tsc --noEmit --pretty false` → **exit 0** Verdict QA: **vert sur le scope tickets `#157` + `#171`**. ### Git / intégration locale - Commit backend: `d6306bb5` — `fix(codex): intention pré-MCP reclassée en Announcement + doublon ToolActivity supprimé (#157 #171)` - Commit frontend: `9fe87a86` — `fix(cli): déduplication métier des cartes progress + délégations rendues une fois (#157 #171)` - Commit miroir tickets: `1beeed8c` — `chore(tickets): sync miroir #157 #171 — QA verte ciblée (AppImage en attente)` - Merge local vers `develop`: `fa613674` — `merge(codex/cli): cycle #157 #171 — dedup cartes tool/MCP + intention pré-MCP live` ### Réserve explicite avant fermeture définitive - **Pas encore de preuve E2E/AppImage live** sur le binaire utilisateur final. - Un rouge Rust global subsiste mais est **préexistant et hors scope**: `crates/infrastructure/tests/mcp_server.rs:777` attend 37 tools alors que le catalogue en expose 38 (`idea_context_update` en plus). ### Statut décidé - Ticket laissé en **QA** et non fermé, dans l'attente d'une validation live AppImage par l'utilisateur. - Si le live confirme: le ticket pourra être fermé sans nouveau cycle de correction. --- ## Itération 3 — 2026-08-10 — Régression CLI custom: doublons tool/MCP + progress potentiellement manquants avant le premier MCP **Remontée user (capture live AppImage, 2026-08-10)** : sur la CLI custom, l'usage de `idea_ask_agent` affiche les événements tool/MCP en double (deux cartes `Delegation idea_ask_agent` et deux cartes `Provider tool: idea_ask_agent`) alors que l'attendu produit est de ne conserver qu'une première carte `start` et une première carte `done`. En parallèle, l'utilisateur suspecte que tous les messages de progression/intention ne sont pas surfacés, notamment possiblement avant le premier appel MCP (ex. "Je vais d'abord regarder la liste de tools MCP..."). ### Arbitrage Main + Architect - **#157 reste le ticket principal du rendu CLI custom** pour la hiérarchie visuelle et le dédoublonnage des cartes tool/MCP/delegation. - **#171 porte la pipeline d'observabilité live** (`ReplyEvent::Progress -> UI`) pour les progress/messages d'intention qui ne doivent pas dépendre du `Final`. - **#167 reste fermé** : le bug historique traité sur l'ordre `events after Final` n'est pas rouvert à ce stade ; si DevBackend démontre un nouveau défaut d'émission/ordering backend, il faudra alors créer un delta dédié ou rouvrir en second temps. ### Hypothèse de travail pour ce cycle - Le backend expose déjà une part significative des progress live via la fondation #156 et le correctif OpenCode de l'itération 2. - Le symptôme utilisateur courant est **probablement** un split : 1. problème frontend de réconciliation/rendu (dédoublonnage des cartes `start/done`), et/ou 2. défaut de projection live UI de certains `ReplyChunk::Progress` en amont du premier appel MCP. ### Cycle relancé - Architect consulté pour arbitrage ports/contrats/tickets. - Décision Git préparatoire récupérée : branche de cycle existante `fix/171-conversation-observability-pipeline` à privilégier, sauf preuve backend contraire. - DevBackend mandaté pour vérifier si les progress pré-MCP existent bien dans le flux backend actuel et si les doublons tool/MCP naissent avant ou après transport UI. - DevFrontend mandaté pour inspecter la logique de rendu/réconciliation des cartes progress/tool/MCP/delegation dans la custom CLI, corriger si nécessaire et préparer les tests. - QA passera après implémentation réelle avec preuve de commandes/tests. ### Attendus de validation pour clôture - Pour un appel `idea_ask_agent`, la CLI custom n'affiche qu'une carte `start` et une carte `done` pertinentes, sans doublons parasites. - Les messages de progression/intention disponibles dans le flux sont visibles **avant** le premier MCP quand ils existent réellement côté provider/IdeA. - Aucun faux streaming n'est simulé pour les profils qui n'exposent pas ce niveau de granularité. --- ## Itération 2 — 2026-08-09 — Régression profil OpenCode/GLM (pas de progress, pas de bulle MCP) **Remontée user** : sur la CLI custom avec un profil OpenCode/GLM, aucun message de progress pendant le traitement de l'agent, et aucune bulle d'appel de tool MCP quand l'agent invoque un outil. ### Cause racine (vérifiée en source opencode v1.17.18) J'ai lu `packages/opencode/src/cli/cmd/run.ts` (sst/opencode). `opencode run --format json` émet chaque événement JSONL **en temps réel** sur stdout (`{type, timestamp, sessionID, ...data}`). Types émis : `step_start`, `step_finish`, `text` (part textuelle finalisée, pas un delta token), `tool_use` (**seulement à** `part.state.status=completed|error`, pas de start), `reasoning`, `error`. Le parser IdeA `opencode.rs::parse_jsonl_record` reconnaît déjà ces types correctement — **le parser n'était pas cassé**. Les deux vraies causes : 1. `OpenCodeSession` ne surchargeait **pas** `send_with_tap` (défaut `domain/ports.rs:1380` ignore le tap). Son `send` bufferisait TOUT le stdout jusqu'à l'EOF puis parsait en bloc → le tap live (`commands.rs:2301`) recevait zéro event pendant le tour (silence total), tout arrivait en burst à la fin. 2. La bulle `kind:Mcp`/`source:IdeaLocal` n'était émise que par `openai_compat.rs::apply_tool_calls` (où IdeA orchestre les outils). Pour OpenCode, les outils tournent **dans** opencode ; les `tool_use` étaient taggés `kind:Tool` générique. ### Correctif livré (backend-only) Branche `fix/ticket157-opencode-progress-mcp-surfacing`, commit `836137a3` (base `develop` `a3d94d4d`). Fichier unique : `crates/infrastructure/src/session/opencode.rs` (+408/−69). - **`send_with_tap` override** (pattern codex.rs/claude.rs) : lecture stdout ligne par ligne, projection live au tap des events non-terminaux (Progress/TextDelta/ToolActivity/Heartbeat), Final assemblé à la fin (jamais envoyé au tap). `send()` sans tap reste batch (inchangé). - **Tagging MCP** : `tool_use` préfixé `idea_` → `ReplyProgress{source:IdeaLocal, kind:Mcp, stage:Completed, tool_name}` (remplace la Progress Tool provider-native, pas de double card). - **Protection replay** : sur session continuée (`--session`), le premier messageID est tamponné puis supprimé si un nouveau messageID arrive (évite de projeter l'historique rejoué). ### Tests & QA - 3 nouveaux tests : `parse_jsonl_turn_tags_idea_tools_as_mcp_progress`, `send_with_tap_emits_progress_live_before_final_and_tags_idea_tool_as_mcp`, `send_with_tap_does_not_replay_previous_message_into_live_stream`. - `cargo test -p infrastructure session::opencode` → **20 passed**. `cargo check -p infrastructure -p application` → OK. `cargo fmt --check` → OK. - QA verdict **VERT** : ciblé conforme au contrat, pas de régression. Les échecs larges (`mcp_server tools_list...` 38 vs 37 ; `orchestrator_service` 39 hangs/spawn) reproduisent **à l'identique sur la base `a3d94d4d`** → pré-existants, hors périmètre du fix. ### Restes / points pour les prochaines itérations - **Réserve replay (tradeoff UX)** : sur une session continuée avec un **seul** messageID et aucun replay observable, le tap peut rester muet jusqu'à l'EOF (`hold_until_new_message`) pour éviter d'afficher un historique non rétractable. Cas frais = streaming immédiat. À retravailler si la reprise de session devient prioritaire. - **`reasoning` non mappé** (dette) : opencode émet des events `reasoning` (thinking) que le parser ignore (`Ignored`). Hors périmètre de ce fix ; ticket dédié à créer si on veut afficher le thinking OpenCode. - **Granularité honnête** : opencode JSON ne donne ni deltas de tokens ni tool-start — seulement step_start/step_finish + text(finalisé) + tool_use(completed). Le fix reste honnête (pas de faux stream simulé), conforme aux critères d'acceptation sur profils pauvres. - **Vérif live en attente** : build AppImage lancé (artefact `target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage`). Le user doit remplacer l'AppImage installée + relancer IdeA pour valider en live (⚠️ relance = tue l'orchestrateur courant). Branche non mergée dans `develop` en attente de vérif live verte (Git ferait le fast-forward ensuite). - **Frontend** : aucun changement requis (`CustomAgentChatView`/`ProgressBubble` gèrent déjà `Progress{Tool|Mcp}` + délégations). Si le rendu live révèle un souci visuel (spinner qui ne s'arrête pas — cf. description initiale du ticket), ce sera un delta frontend ciblé. --- # Objectif Améliorer la CLI custom / chat agent pour afficher **un maximum de progress intermédiaires réellement disponibles** au lieu d'un silence jusqu'au `Final`, avec une UX différenciée pour : - les messages/progress agent généraux - les appels MCP / outils - les délégations inter-agent # Dépendance - Dépend explicitement de #156, qui doit fournir le contrat d'événements canonique multi-profils. # Attentes produit - Afficher les événements intermédiaires au fil de l'eau quand ils existent. - Montrer clairement quel agent parle à quel agent. - Afficher un extrait court de la demande déléguée. - Rendre les appels MCP/outils visuellement distincts du reste du flux. - Fonctionner avec un maximum de profils IA, avec dégradation élégante quand un profil n'expose pas grand-chose. # Périmètre UI/UX attendu ## Types visuels - `AgentMessage` : message/progress principal d'un agent. - `Delegation` : carte dédiée `Agent A -> Agent B` avec extrait court de la demande. - `ToolCall` : carte secondaire/indentée pour les appels d'outil. - `MCPEvent` : variante spécifique pour les appels MCP/méthodes MCP, distincte visuellement. ## États - `started` - `running` - `done` - `error` ## Hiérarchie visuelle - Les délégations et appels MCP ne doivent pas se confondre avec un simple texte agent. - Les appels MCP/outils doivent être lisibles mais plus discrets que le message principal. - Prévoir la lecture d'une conversation longue sans transformer l'écran en log brut. # Recommandations UX initiales (retour UX intégré) - `Delegation` : carte avec flèche `From -> To`, extrait de demande tronqué (~80 chars), accès au détail sur expansion/hover. - `ToolCall` : carte indentée avec badge outil, état spinner/check/error, args résumés/tronqués. - `MCPEvent` : bordure latérale/coloration dédiée par serveur ou type de méthode. - Timeline verticale légère pour relier visuellement les sous-événements au message/agent source. - Les événements très courts doivent être lissés/batchés pour éviter le clignotement. # Anti-bruit / garde-fous - Ne pas afficher comme texte brut tous les micro-événements sans hiérarchie. - Seuil temporel ou batching pour les événements trop fugitifs. - Possibilité de collapse/groupement pour tool calls répétitifs. - Limitation du nombre d'événements visibles avant expansion. - Si un profil n'expose aucun delta ni événement intermédiaire, afficher au minimum l'état occupé/vivant sans simuler un faux stream. # Critères d'acceptation - Sur les profils riches, l'utilisateur voit les progress/events apparaître avant le `Final`. - Sur les profils pauvres, l'UI reste honnête et utile (busy/progression minimale) sans faux "thinking". - Les appels MCP apparaissent au fil de l'eau, pas seulement après le `Final`, si l'information est disponible côté IdeA. - Les délégations inter-agent sont lisibles : on comprend qui parle à qui et à propos de quoi. - La vue reste stable et lisible sur conversation longue.