tape-fold: don't synthesize tool results for aborted assistant messages - #239
Merged
Conversation
A user abort mid-stream leaves an assistant message with stopReason 'aborted' that contains a completed toolCall block but no tool result (the tool never ran). The interrupt heal then synthesized an INTERRUPTED_TOOL_RESULT for that call. But pi's transformMessages drops aborted/errored assistant messages entirely at request time while keeping every toolResult message, so the healed result reached the provider as a tool_result with no corresponding tool_use — a 400 (invalid_request_error) on every subsequent step, permanently wedging the session. Skip aborted/errored assistant messages when collecting dangling calls (they are never replayed, so their calls need no results), and make lintFold reject a fold where a toolResult answers such a call, so a poisoned fold falls back to entry-based replay instead of being served. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…in tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a user aborts a turn while the model is mid-stream, pi commits the partial assistant message with
stopReason: "aborted". If the abort landed after a completetoolCallblock, that message contains a tool call that never executed and has no tool result.The tape fold treated that call as dangling:
tapeNeedsInterruptHealflagged it, aninterruptevent was appended, andhealDanglingCallssynthesized anINTERRUPTED_TOOL_RESULTfor it. But pi'stransformMessagesdrops aborted/errored assistant messages entirely when building the provider request, while keeping everytoolResultmessage. The healed result therefore reached the provider as atool_resultblock with no correspondingtool_usein the previous message:Every subsequent step re-serves the same fold, so the session is permanently wedged: each turn fails with the same 400.
Fix
healDanglingCallsskips assistant messages withstopReason"aborted"/"error"when collecting dangling calls. Those messages are never replayed, so their calls need no results — and synthesizing one is what poisons the request.lintFoldno longer counts such messages' calls as open. AtoolResultanswering one now lints as a problem, so a fold that would orphan a result on the wire falls back to entry-based replay instead of being served.The interrupted-result heal is unchanged for the case it exists for: a restart mid tool execution, where the assistant message completed normally (
stopReason: "toolUse") and is replayed.Testing
lintFoldrejects a fold where atoolResultanswers an aborted assistant's call.node --test test/tape-fold.test.ts— 26/26 pass;tsc --noEmitand eslint clean.Reproduced against a live session: abort a turn while the model is streaming a tool call, then send another message — before this fix every subsequent turn 400s with the error above.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.