fix(session): fail loudly when the MCP re-prompt cap is exhausted (#435)
When the MCP re-prompt loop hit its 3-round cap and the model was still asking for a tool call, apfel stripped the pending tool-call JSON and returned whatever text was left as a successful answer. The caller got finish_reason: stop and no indication that tool work had been abandoned half-way -- a partial answer presented as a complete one. Stripping the raw JSON is correct and stays correct: it must never reach the user as text (#187, #358). Reporting the remainder as a normal completion is the part that was wrong. Both paths now throw ApfelError.toolExecution, which maps to a 500 server_error -- the right classification, since the model failing to converge is a server-side failure, not a caller mistake. Candidate PR #447 fixed only the CLI path, leaving the HTTP path -- the one that actually returns finish_reason to a client -- unchanged. #452 was taken instead: it covers both, and it puts the check in ApfelCore as ensureToolLoopCompleted with the cap as a single shared constant, so the two paths cannot drift apart again. The local stripToolCallJSON wrapper in Session.swift became unreferenced and was removed; the ApfelCore implementation and its #358 tests stay. 1107 unit tests pass. Closes #435 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ccLBbEaVVd4sJyUd5wyhA
A
Arthur Ficial committed
d0984ad877d5d4a22ef70eef52b097fe37d8da8e
Parent: 68a62f2