Skip to content

fix: interrupt tool call 400 error — clean up assistant tool-call message on interrupt#446

Merged
avoidwork merged 2 commits into
mainfrom
feat/fix-interrupt-tool-call-400-error
Jun 25, 2026
Merged

fix: interrupt tool call 400 error — clean up assistant tool-call message on interrupt#446
avoidwork merged 2 commits into
mainfrom
feat/fix-interrupt-tool-call-400-error

Conversation

@avoidwork

Copy link
Copy Markdown
Owner

Description

Fix the unrecoverable 400 error that occurs when interrupting a tool execution in the TUI. The root cause is that handleInterrupt() only removes the user's message from session state, but leaves the assistant's partial AIMessage (containing tool_calls that were never completed) in the conversation history. On resume, this corrupted message sequence causes the LLM API to reject the request with 'system message must be at the beginning.'

Type of Change

  • Bugfix (non-breaking change which fixes an issue)

Testing

Unit tests added for removeLastAssistantToolCallMessage() covering:

  • Assistant message with tool_calls present (should be removed)
  • Assistant message without tool_calls (should not be removed)
  • No assistant message (no-op, safe)
  • Empty conversation (no-op, safe)

Integration test for handleInterrupt() cleanup behavior:

  • Interrupt during tool execution
  • Interrupt during text response
  • Interrupt with no assistant message

Coverage

  • 100% line coverage maintained

Checklist

  • npm run lint passes
  • Tests pass with 100% line coverage
  • No forbidden patterns used
  • Conventional Commit style applied

Related Issue

Closes #444

@avoidwork

Copy link
Copy Markdown
Owner Author

Audit Results: Fix Interrupt Tool Call 400 Error

Audit 1 (Implementation Against Specs & Goals)

Goal Fulfillment

  • Goal 1 (Fix handleInterrupt to clean up assistant tool-call message) → ALL KEY REQUIREMENTS SATISFIED
    • Key Requirement 1: removeLastAssistantToolCallMessage() called in both handleInterrupt() and AbortError catch block ✓
    • Key Requirement 2: Session state reset to consistent state (assistant tool-call message + user message removed) ✓
    • Key Requirement 3: Cleanup happens before next dispatch (in handleInterrupt before dispatchPromise resolves, and in AbortError catch block) ✓
  • All 4 acceptance criteria met:
    • Interrupting a tool execution no longer produces a 400 error on resume ✓
    • The conversation continues normally after interruption ✓
    • The session state is consistent (no orphaned AIMessages with tool_calls) ✓
    • The system message remains at position 0 in the messages array sent to the LLM API ✓

Spec Compliance

  • Requirement 1 (Interrupt cleanup removes assistant tool-call messages) → All 3 scenarios covered ✓
  • Requirement 2 (Cleanup helper is idempotent and defensive) → All 2 scenarios covered ✓
  • Requirement 3 (Cleanup occurs before next LLM dispatch) → Scenario covered ✓

Task Completion

  • All 12 tasks marked [x] ✓
  • Tasks 1.1-1.3: Helper method added to src/session/stateManager.js
  • Tasks 2.1-2.2: handleInterrupt() updated in src/tui/app.js
  • Tasks 3.1-3.2: AbortError catch block updated in src/tui/app.js
  • Tasks 4.1-4.2: Unit tests added to tests/unit/session.test.js
  • Tasks 5.1-5.3: Verification passed (lint clean, 1183 tests pass, app starts) ✓

Quality Check

  • Implementation is clean and focused — only 3 files changed (stateManager.js, app.js, session.test.js)
  • Helper is idempotent and defensive — safe to call when no matching message exists
  • Tests cover all required scenarios including edge cases (empty conversation, no assistant message, text response)
  • Code follows existing patterns in the codebase
  • No forbidden patterns used (no console.log, no silent catches, no eval)

Result

No errors found. Implementation fully satisfies all goals, specs, and tasks.

@avoidwork avoidwork merged commit 6dca5c6 into main Jun 25, 2026
2 checks passed
@avoidwork avoidwork deleted the feat/fix-interrupt-tool-call-400-error branch June 25, 2026 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: interrupting a tool causes unrecoverable 400 error

1 participant