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.23 (omp 18.12.6): every turn refused on resumed sessions: prepared turn structure ... expectedRole=missing actualRole=system comparison=count (trailing omp tool-control system message isn't modeled) #785
Symptom
After the upgrade, every turn on sessions created before the upgrade is refused. Brand-new sessions work.
Magic Context could not safely prepare this turn; send your message again. stage=provider dispatch ... refused (provider request does not match this pass's managed dispatch (prepared turn structure); row=11 expectedRows=11 actualRows=12 expectedRole=missing actualRole=system expectedCalls=0 actualCalls=0 expectedResults=0 actualResults=0 comparison=count)
Retrying doesn't help: expectedRows grows by 2 per attempt and the provider payload always has exactly one extra row at the end.
Cause
We logged the last 3 provider messages at the mismatch, just before the throw in the dispatch check. The extra row is omp's request-control message, a trailing system message holding only tool_addition blocks:
omp's Anthropic provider (pi-ai/src/providers/anthropic.ts) inserts these tool-change and effort controls via insertAnthropicControlMarkers while it builds the request. That happens after MC's context pass, so the prepared plan never contains the row. payloadStructure only skips system/developer messages while rows.length === 0, so the trailing control is counted as a conversation row and the count comparison fails.
The control appears when the session's recorded tool set differs from the current one, which is why only resumed pre-upgrade sessions hit it. The control is only recorded after a successful request, and the refusal prevents that, so the session can never recover by itself.
Local fix (verified)
In payloadStructure, right after the leading system/developer skip:
With this, the previously refused session replies normally and new sessions are unaffected. Empty effort-only controls (content: []) are also skipped, because every on an empty array is true.
Suggested upstream fix: treat omp request controls (tool_addition / tool_removal / effort-only system params) as non-conversation rows in the structure comparison. Alternatively, model them in the prepared plan the same way omp's planAnthropicEffortControls / tool plan does.
Repro (observed path; not reproduced from scratch)
On omp 18.12.3 + MC 0.49.13, create a session with Opus 5.5 and send a few turns.
Upgrade to omp 18.12.6 + MC 0.49.23.
Resume the session and send any message: refused on every attempt.
Thanks for the precise diagnosis and the logged payload. That made this quick to confirm.
It matches our code: the Pi dispatch check only skips system/developer rows that come before the first conversation row, so Oh My Pi's trailing request-control message (the tool_addition blocks) is counted as an extra conversation row and the count comparison refuses the turn. And because Oh My Pi only records the control after a successful request, the session can't get past it on its own.
The likely reason only older sessions hit it: since 0.49.20, Magic Context's tools are always loaded on Oh My Pi rather than discovered on demand, so a session started before that sees its tool set change on the first turn after upgrading, and Oh My Pi adds the control for the five ctx_* tools.
Until a fix ships, new sessions aren't affected, so starting a new session is the workaround for anything you need to keep working on. We'll follow up here with the fix.
Fixed in 0.49.24, with your PR #786. Thanks @tsankotsanev for both the report and the fix.
The Oh My Pi request check now skips the tool-control messages Oh My Pi adds when a session's tool list changes, wherever they appear in the request. Resumed sessions no longer have every turn refused. A message that carries real text in that position is still refused, as before.
Update the Pi package and restart Oh My Pi to pick it up.
Activity
magic-alfonso commentedon Oct 26, 2026
Thanks for the precise diagnosis and the logged payload. That made this quick to confirm.
It matches our code: the Pi dispatch check only skips
system/developerrows that come before the first conversation row, so Oh My Pi's trailing request-control message (thetool_additionblocks) is counted as an extra conversation row and the count comparison refuses the turn. And because Oh My Pi only records the control after a successful request, the session can't get past it on its own.The likely reason only older sessions hit it: since 0.49.20, Magic Context's tools are always loaded on Oh My Pi rather than discovered on demand, so a session started before that sees its tool set change on the first turn after upgrading, and Oh My Pi adds the control for the five
ctx_*tools.Until a fix ships, new sessions aren't affected, so starting a new session is the workaround for anything you need to keep working on. We'll follow up here with the fix.
pi: skip Oh My Pi request-control system rows in the dispatch check
magic-alfonso commentedon Oct 27, 2026
Fixed in 0.49.24, with your PR #786. Thanks @tsankotsanev for both the report and the fix.
The Oh My Pi request check now skips the tool-control messages Oh My Pi adds when a session's tool list changes, wherever they appear in the request. Resumed sessions no longer have every turn refused. A message that carries real text in that position is still refused, as before.
Update the Pi package and restart Oh My Pi to pick it up.