You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
0.49.22 (omp 18.13.0): after an aborted turn, every Anthropic turn is refused with prepared turn structure … expectedRows > actualRows comparison=role (empty-text aborted assistant dropped by omp, kept by the fence) #794
On the Anthropic Messages lane, once a turn has been refused and aborted, every later turn in that session is refused:
stage=provider dispatch … refused (provider request does not match this pass's managed dispatch (prepared turn structure);
row=3 expectedRows=7 actualRows=5 expectedRole=assistant actualRole=user
expectedCalls=0 actualCalls=0 expectedResults=0 actualResults=0 comparison=role)
Retrying, or sending the session a new message, never helps. The wire always has fewer rows than the prepared structure, and the gap equals the number of aborted assistant turns whose content is a single empty text block.
Environment
@cortexkit/pi-magic-context 0.49.22
omp 18.13.0, provider api anthropic-messages (Claude)
On the next pass, the prepared structure keeps that assistant row.
omp's Anthropic converter (@oh-my-pi/pi-aiproviders/anthropic.ts, assistant branch of the message conversion) skips text blocks where text.trim().length === 0, and then skips the whole message when blocks.length === 0. The aborted turn is gone from the wire, so the next row is the following user/developer message: expectedRole=assistant actualRole=user.
That refusal aborts again. This time the persisted message has content: [], which both sides drop (it matches shouldDropTruncatedThinkingOnlyAssistant), so the gap stays constant and every pass refuses.
Two sessions, each pass in order (the delta stays at the number of ""-text aborted turns):
session
aborted turns with [{text:""}]
refusals (expected / actual rows)
1
2
7/5, 8/6, 9/7
2
1
5/4, 6/5, 7/6, 8/7
The same abort on the OpenAI Responses lane (same [{text:""}] content) is not affected, and those sessions recovered on the next served pass.
Suggested direction
Model the Anthropic converter's drop of an assistant message whose blocks are all whitespace-only text (in addition to the existing truncated-stop rule), or
don't persist an empty text block on the aborted message the refusal produces, or
Thanks for the precise report. The cause is as you describe. Oh My Pi's Anthropic converter skips text blocks that are empty or whitespace-only, and it then drops an assistant message that has no blocks left. The aborted turn's [{type: "text", text: ""}] therefore never reaches the wire. Magic Context's request check still counts that row, so the row count stays off by one for each such turn, and every later pass is refused. The OpenAI Responses route sends the empty message, which is why it recovers there.
We're preparing a fix that models this drop in the request check, using the same converter rules for each supported Oh My Pi version. Until it ships, starting a new session avoids the loop.
Fixed in 0.49.24. Thanks @TheOrdinaryWow for the report and the trace.
After an aborted turn, Oh My Pi drops an assistant reply that has no blocks left, and Magic Context's request check now models that drop, using rules read from Oh My Pi's source for each supported version (18.12.3, 18.12.6 and 18.13.0). Later Claude turns are no longer refused. On a real Oh My Pi 18.13.0 session, the previous build refused every turn after one aborted turn and this build replies.
One narrow case still refuses rather than guesses: a model configured to replay thinking from another provider, whose thinking is then dropped at request time. If you hit that, please open an issue with the log line.
Update the Pi package and restart Oh My Pi to pick it up.
Activity
magic-alfonso commentedon Oct 26, 2026
Thanks for the precise report. The cause is as you describe. Oh My Pi's Anthropic converter skips text blocks that are empty or whitespace-only, and it then drops an assistant message that has no blocks left. The aborted turn's
[{type: "text", text: ""}]therefore never reaches the wire. Magic Context's request check still counts that row, so the row count stays off by one for each such turn, and every later pass is refused. The OpenAI Responses route sends the empty message, which is why it recovers there.We're preparing a fix that models this drop in the request check, using the same converter rules for each supported Oh My Pi version. Until it ships, starting a new session avoids the loop.
magic-alfonso commentedon Oct 27, 2026
Fixed in 0.49.24. Thanks @TheOrdinaryWow for the report and the trace.
After an aborted turn, Oh My Pi drops an assistant reply that has no blocks left, and Magic Context's request check now models that drop, using rules read from Oh My Pi's source for each supported version (18.12.3, 18.12.6 and 18.13.0). Later Claude turns are no longer refused. On a real Oh My Pi 18.13.0 session, the previous build refused every turn after one aborted turn and this build replies.
One narrow case still refuses rather than guesses: a model configured to replay thinking from another provider, whose thinking is then dropped at request time. If you hit that, please open an issue with the log line.
Update the Pi package and restart Oh My Pi to pick it up.