Bugfix: S185: Why did the Vitto agent loop fail with Claude API 400 ...
Documentation for Sessions
🐛 Bugfix: S185: Why did the Vitto agent loop fail with Claude API 400 ...
Date: 2026-03-07
Time: 01:37:10 UTC
Session: gspace1-185.5
Agent: backend
Confidence: 96%
Status: ✅ Documented
📋 Decision Context
Question:
S185: Why did the Vitto agent loop fail with Claude API 400 'tool_use ids without tool_result blocks'?
Task: S185: Fix module generation failing with Claude API 400 error
🎯 Decision Made
Chosen:
Two fixes: (1) agent-loop.service.ts: Added tool_result backfill loop after tool execution — scans for any tool_use IDs without matching tool_result and adds placeholder results. (2) Deferred stuck-detection user message injection to AFTER tool_result backfill — Claude requires tool_result immediately after tool_use, user messages between them cause 400.
Options Considered:
- Fix only the stuck-detection path (misses task_complete path)
- Add tool_result backfill for all early-exit paths (chosen - comprehensive)
- Restructure agent loop to always execute all tools before breaking (too invasive)
💭 Reasoning
Root cause chain: When stuck detection fired 'summarize_context', the code at line 323 pushed a user message BETWEEN the assistant(toolCalls) message and the tool execution block. Then shouldBreakInner=true skipped tool execution entirely. Result: assistant message had tool_use blocks, next message was a user message (not tool_result), violating Claude API contract. Secondary: when task_complete was found mid-batch, remaining tool_use blocks in the same response had no tool_result messages added. The backfill loop at line 494 now ensures every tool_use has a matching tool_result regardless of early exit path.
📁 Files Involved
APIs/backend-vitto-api/src/app/engine/agent-loop.service.tsAPIs/backend-vitto-api/src/app/llm/providers/claude.provider.ts
🔗 Related
- Decision ID:
dev_1772847430330_w8ndxap - Session: 185
- Workspace: gspace1
Auto-generated by MCP Smart Consolidation