Skip to content

feat: Add Error Interception Middleware for guided AI self-correcting tool errors #1000

Description

@myk1yt

Problem

When the AI model makes structural mistakes (e.g., passing cwd as an object instead of a string, nesting tool calls inside parameters, or emitting XML tool markup alongside native tool calls), Zoo Code currently:

  1. Shows raw error messages that the AI cannot parse or learn from
  2. Repeats the same mistake until consecutiveMistakeLimit is reached
  3. Displays an interactive "Continue" button that freezes the workflow until the user manually intervenes

This affects all models but is especially prevalent with MiMo models, where ~80% of diagnostics show CWD_OBJECT_MISUSE as the dominant failure mode.


Related Issues

This middleware addresses or provides infrastructure for the following existing bug reports:

Directly Covered by This Middleware

Issue Title Pattern Coverage How Middleware Helps
#752 Shell Integration Warning when using MiMo SHELL_INTEGRATION/001 When shell integration fails, middleware returns a guided message telling the AI to use non-shell tools instead of looping. Prevents the 10+ consecutive failure spiral described in the issue.
#704 Shell Integration Error persists after long sessions SHELL_INTEGRATION/001 Same as #752. The dead terminal reuse infinite loop is mitigated by the MODEL_STUCK_LOOP circuit breaker — after 3 failures, the AI is directed to change strategy entirely.
#800 Terminal cannot capture results, dialog stuck MODEL_STUCK_LOOP The circuit breaker prevents the "stuck at Running" state by resetting consecutiveMistakeCount and directing the AI to try a different approach after 3 occurrences.
#794 Errors Produced by Open Weight Models + Solutions All patterns This issue's community patches (Guide G1/G2/G3, XML fallback P1) are the direct inspiration for this middleware. Our middleware formalizes the "guide the AI" philosophy into official, testable infrastructure with 9+1 categorized patterns instead of minified extension.js patches.
#547 DeepSeek 5 structural tool-calling defects PARAM_MISSING, XML_NATIVE_DUAL_PROTOCOL, CONTEXT_OVERFLOW Defect 1 (Missing Required Parameters) → PARAM_MISSING/001 pattern. Defect 4 (XML Tag Fallback) → XML_NATIVE_DUAL_PROTOCOL pattern strips XML and guides to native tool_use. Defect 3 (reasoning_content loss) → CONTEXT_OVERFLOW/001 auto-recovery.
#709 Tool call serialization failure - XML output XML_NATIVE_DUAL_PROTOCOL When mimo-v2.5-pro outputs XML tags alongside native calls, middleware strips the XML from visible text and merges a protocol guide into the native tool's result. The AI sees "Use native tool_use only" and self-corrects.
#707 Chat output truncation at 8KB - XML tool calls as raw text XML_NATIVE_DUAL_PROTOCOL Same pattern as #709. Middleware detects XML markers in text blocks and strips them before rendering. Combined with the 10,000-char text-length guard to prevent over-stripping on very long responses.
#695 Streaming tool-call argument deltas silently dropped PARAM_MISSING/001 When streaming data loss causes missing parameters, the PARAM_MISSING pattern returns a guided message with the tool's required parameters and correct usage example, instead of a cryptic "missing nativeArgs" error.
#459 Claude model proxy errors/spinning MODEL_STUCK_LOOP When the model enters an error loop, the circuit breaker at occurrence 3 resets consecutiveMistakeCount and issues a [MODEL_STUCK_LOOP] directive. The interactive "Continue" button is suppressed — the AI self-corrects.
#458 Requests keep spinning MODEL_STUCK_LOOP Same circuit breaker mechanism. Prevents indefinite spinning by directing the AI to change strategy.

Indirectly Related (Middleware Provides Partial Coverage)

Issue Title Relationship
#648 Un-controllable Token Exceed with MCP results CONTEXT_OVERFLOW/001 pattern provides auto-recovery guidance when context window is exceeded. Does not prevent the overflow itself, but guides the AI to compress or continue from summary.
#427 Shell-integration polling refactor SHELL_INTEGRATION/001 handles the error gracefully when shell integration fails, regardless of the underlying polling mechanism. Complementary fixes.
#471 Infinite JSON tool loop on Ollama MODEL_STUCK_LOOP circuit breaker prevents infinite loops. Does not fix the Ollama tool-calling detection issue itself.

Not Covered (Outside Middleware Scope)

Issue Reason
#257 Chat stuck on "API Request" — UI state management issue, not tool error
#877 Ollama model refresh stuck — settings panel UI issue
#937 Message processing order at terminal finish — task lifecycle issue
#856 Task Tree Abstraction — architecture enhancement
#464 Universal AI Clipboard — new feature proposal

Image

Originally, you had to click the 'Proceed Anyway' button to proceed in this state, but I changed it to a format that guides the AI to perform the correct task, as shown below.

Image Image

Solution: Error Interception Middleware

A new middleware layer that intercepts, classifies, and transforms tool errors into actionable guidance messages, enabling the AI to self-correct without user intervention.

Architecture

Tool Error → ErrorClassifier → ErrorPattern DB (9+1 categories)
                                    ↓
                              MessageTransformer → Versioned JSON guidance
                                    ↓
                              TaskErrorState (WeakMap) → Circuit Breaker
                                    ↓
                              Exactly one guided tool_result → AI self-corrects

New Modules

Module Purpose
errorPatterns.ts Pattern DB with 9+1 error categories and variant entries
ErrorClassifier.ts Deterministic error classifier (priority-ordered pattern matching)
MessageTransformer.ts Versioned JSON guidance serializer (WHAT/WHY/NEXT format)
TaskErrorState.ts Task-scoped persistent state via WeakMap (occurrence tracking, circuit breaker)
StructuralValidator.ts CWD object detection + nested parameter overflow detection
ToolErrorInterceptor.ts Interceptor facade (transformError, circuit status)

Error Patterns Covered

# Category Pattern ID Trigger Behavior Related Issues
1 DUPLICATE_CALL EI/DUPLICATE_CALL/001 Repeated identical tool call Block + guide
2 PARAM_MISSING EI/PARAM_MISSING/001 Required parameter missing Block + guide with example #695, #547 Defect 1
3 PARAM_TYPE_MISMATCH EI/PARAM_TYPE_MISMATCH/001 Generic type mismatch Block + guide
4 PARAM_TYPE_MISMATCH EI/PARAM_TYPE_MISMATCH/002 CWD passed as object Block + guide "cwd must be a string"
5 PARAM_TYPE_MISMATCH EI/PARAM_TYPE_MISMATCH/003 Nested tool invocation in param Block + guide "issue separate calls"
6 FILE_NOT_FOUND EI/FILE_NOT_FOUND/001 File/directory not found Guide to use list_files
7 SHELL_INTEGRATION EI/SHELL_INTEGRATION/001 Shell integration failure Guide to use non-shell tools #752, #704, #427
8 MCP_TOOL_MISSING EI/MCP_TOOL_MISSING/001 MCP tool/server not found Guide to select from list
9 INVALID_TOOL_PROTOCOL EI/INVALID_TOOL_PROTOCOL/001 XML tool calls in text Strip XML + guide #709, #707
10 INVALID_TOOL_PROTOCOL EI/INVALID_TOOL_PROTOCOL/002 XML + native dual protocol Strip XML + merge protocol guide #709, #707, #547 Defect 4
11 CONTEXT_OVERFLOW EI/CONTEXT_OVERFLOW/001 Context window exceeded Auto-recovery guide #648, #547 Defect 3
12 MODEL_STUCK_LOOP (circuit breaker) Same error 3x Strategy change directive, no user prompt #800, #459, #458, #752, #704

Circuit Breaker (MODEL_STUCK_LOOP)

Occurrence Behavior
1 Guided correction (variant-specific message)
2 Strengthened guidance ("Re-read the tool schema now")
3 Circuit opens — [MODEL_STUCK_LOOP] directive, consecutiveMistakeCount reset, no user prompt

Design Philosophy (from #794)

"We have two options: (1) Suppress error messages and let the AI self-correct, (2) When the AI exhibits a bad habit that causes errors, guide it toward the correct approach. We prefer option 2."

This middleware implements option 2 as official, testable infrastructure. Each error produces a WHAT/WHY/NEXT guidance payload that tells the AI:

  • WHAT went wrong (specific, not generic)
  • WHY it happened (root cause, not symptom)
  • NEXT what to do (actionable steps, not vague advice)

Before vs After

Scenario Before After
AI sends cwd: {command: "..."} Terminal error → raw message → AI repeats → user must click Continue Preflight blocks → guided tool_result with "cwd must be a string" → AI self-corrects
AI emits XML + native tool call Confusing partial execution → user must intervene (#709, #707) XML stripped, native executes, protocol guide merged
AI nests parallel params in one call Cryptic error → user must Continue Preflight detects nested signature → guided "issue separate calls"
Same mistake 3x consecutiveMistakeLimit → interactive prompt → user must click (#800, #459) Circuit breaker → [MODEL_STUCK_LOOP] → AI changes strategy
Shell integration failure Raw error → AI retries same terminal → infinite loop (#752, #704) SHELL_INTEGRATION/001 guide → AI uses non-shell tools

Test Coverage

  • 113 tests across 7 test files, all passing
  • StructuralValidator: CWD detection, nested param detection, allow-list, cycle detection
  • TaskErrorState: Occurrence tracking, circuit open/close, fingerprint, reset, WeakMap isolation
  • presentAssistantMessage: 7 integration tests (CWD blocked, circuit at occurrence 3, nested overflow, XML+native, etc.)
  • model-stuck-loop: 10 tests (accumulation, threshold, suppression, per-Task isolation)

Files Changed

File Type Description
src/core/tools/error-interception/errorPatterns.ts Modified 3 variant entries (CWD, NESTED, XML_DUAL)
src/core/tools/error-interception/TaskErrorState.ts New Task-scoped persistent state (WeakMap)
src/core/tools/error-interception/StructuralValidator.ts New CWD + nested param detection
src/core/assistant-message/presentAssistantMessage.ts Modified Structural preflight + XML detection + FP-1 fix (classify errors by message content)
src/core/task/Task.ts Modified MODEL_STUCK_LOOP circuit breaker
src/core/tools/error-interception/index.ts Modified Stable exports
Test files (4 new) New 113 tests total

Commits

  • fc38100a6 — feat: complete gap-fix for 4 uncovered error patterns (+1460/-2)
  • 291f4594b — fix: resolve false positive PARAM_TYPE_MISMATCH on validateToolUse failures (+13/-1)

Replaces closed #999 (could not add labels due to repository permissions).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions