# Plan Mode Bug Fix - Claude WebUI **Datum:** 2025-12-16 **Status:** DEPLOYED ## Das Problem Beim Plan Mode Approval im WebUI kam ein API Error: ``` API Error: 400 {"type":"error","error":{"type":"invalid_request_error", "message":"messages.98.content.0: unexpected tool_use_id found in tool_result blocks: toolu_01R6yjX7gqduKgMAuYuPzMeG. Each tool_result block must have a corresponding tool_use block in the previous message."}} ``` ### Ursache - Wenn das WebUI ein Plan Approval sendet, muss die `tool_use_id` mit einem vorherigen `tool_use` Block matchen - Bei **Message History Compaction** gehen die ursprünglichen `tool_use` Blöcke verloren - Das WebUI sendete `tool_result` für Permissions, aber die zugehörigen `tool_use` IDs existierten nicht mehr ## Die Lösung ### 1. Scope-Problem gefixt `setPermissionModeViaControl` wurde aus `startClaudeSession` in den äußeren WebSocket-Scope verschoben: **Datei:** `backend/server.js` (Zeile ~307) ```javascript // Helper to set permission mode via control protocol (needs claudeProcess) const setPermissionModeViaControl = (mode) => { if (!claudeProcess) return; const modeRequestId = generateRequestId(); const modeRequest = { type: 'control_request', request_id: modeRequestId, request: { subtype: 'set_permission_mode', mode: mode } }; console.log(`[${sessionId}] Auto-switching permission mode to: ${mode}`); claudeProcess.stdin.write(JSON.stringify(modeRequest) + '\n'); pendingControlRequests.set(modeRequestId, { type: 'set_permission_mode', mode }); }; ``` ### 2. Permission Responses als `control_response` statt `tool_result` **Datei:** `backend/server.js` (Zeile ~641) ```javascript // All permission responses (including ExitPlanMode/plan approval) use control_response // This avoids tool_result issues when message history is compacted const permResponse = { type: 'control_response', response: { subtype: 'success', request_id: data.requestId, response: data.allow ? { behavior: 'allow', updated_input: data.updatedInput || null } : { behavior: 'deny', message: data.message || 'User denied permission' } } }; ``` ### 3. Plan Mode State Tracking **Datei:** `backend/server.js` (Zeile ~302) ```javascript let inPlanMode = false; // Track if we're in plan mode ``` Bei `ExitPlanMode` Permission Request (Zeile ~441): ```javascript // Track plan mode state for ExitPlanMode if (isPlanApproval && !inPlanMode) { savedPermissionMode = currentPermissionMode; inPlanMode = true; console.log(`[${sessionId}] Entering plan mode, saved mode: ${savedPermissionMode}`); } ``` ## Deployment Nach Code-Änderungen muss das Backend-Image neu gebaut werden: ```bash cd /home/sumdex/projects/claude-web-ui docker compose build backend docker compose up -d backend ``` **Wichtig:** Der Backend-Code ist NICHT als Volume gemountet, sondern im Image gebaut! ### Verifizieren dass der Fix deployed ist: ```bash docker exec claude-webui-backend cat /app/server.js | grep "setPermissionModeViaControl" ``` ## Relevante Dateien | Datei | Beschreibung | |-------|--------------| | `backend/server.js` | Haupt-Backend, WebSocket Handler, Permission Handling | | `frontend/src/hooks/useClaudeSession.js` | Frontend Hook für Claude Session | | `frontend/src/components/PermissionDialog.jsx` | Permission UI Dialog | | `docker-compose.yml` | Container Konfiguration | ## Session-Dump Falls weitere Analyse nötig: ``` /home/sumdex/projects/webui-workspace/session-dump-20251216-164148.jsonl ``` ## Technischer Hintergrund ### Control Protocol vs Tool Results - **tool_result:** Muss immer mit einem `tool_use` in der vorherigen Nachricht matchen - **control_response:** Hat diese Einschränkung nicht, funktioniert unabhängig von Message History ### Message Compaction Claude Code kompaktiert die Message History um Context zu sparen. Dabei können `tool_use` Blöcke entfernt werden, was zu ID-Mismatches führt wenn später `tool_result` mit diesen IDs gesendet wird. ## Test 1. WebUI öffnen: http://100.105.142.13:3000 2. Neue Session starten 3. Eine Anfrage stellen die Plan Mode triggert (z.B. "Implementiere Feature X") 4. Plan Mode Approval im UI bestätigen 5. Es sollte KEIN `unexpected tool_use_id` Error mehr kommen