Skip to content

0.49.23 (omp 18.12.6): prepared turn structure ... comparison=role refusal: dropping a tool call can leave two adjacent assistants, and omp's Anthropic Continue. repair row isn't modeled #789

Closed

Description

@TheOrdinaryWow

Summary

On a resumed omp session (Anthropic Messages API, dispatch fence on, side_contexts=0), every turn is refused:

refused (provider request does not match this pass's managed dispatch (prepared turn structure);
row=22 expectedRows=611 actualRows=616 expectedRole=assistant actualRole=user
expectedCalls=1 actualCalls=0 expectedResults=0 actualResults=0 comparison=role)

Retrying never helps, because the wire always has exactly 5 more rows than the prepared structure.

Environment

  • @cortexkit/pi-magic-context 0.49.23
  • omp 18.12.6, provider api anthropic-messages (claude-sonnet-5-5)
  • Session of ~1,840 entries; it contains 95 todo tool calls

Cause (reproduced)

I reproduced it in an isolated HOME (copied context.db, fake Anthropic endpoint) and instrumented the copy so it dumps active.preparedStructure together with the actual payload at the fence:

  1. MC's transform output keeps only 19 of the session's 95 todo tool calls. It removes the others together with their results.
  2. Five assistant messages consisted of one short text block plus a single todo call (e.g. "Refreshing the todo list, dispatching next." + todo). With the call removed, each becomes a text-only assistant, and the next row in MC's output is also an assistant.
  3. omp's Anthropic converter (@oh-my-pi/pi-ai providers/anthropic.ts, the "Dropped empty user/developer turns can leave two assistant params adjacent" loop) repairs adjacent assistant params by inserting { role: "user", content: "Continue." } between them.
  4. The prepared structure doesn't model that repair. The payload has a user "Continue." row at index 16, 181, 238, 312 and 426, which is 5 extra rows. The first one shifts the comparison so that it fails at row 22 with expectedRole=assistant actualRole=user.

Every pass reproduces it, since the adjacency is produced by MC's own output.

Suggested direction

Either of these would fix it:

Activity

  1. magic-alfonso commented on Oct 26, 2026

    @magic-alfonso

    Thanks for the careful reproduction. Dumping the prepared structure next to the actual payload made this quick to confirm.

    Confirmed. When Magic Context removes an old tool call together with its result, an assistant message that held only short text and that call can end up directly before another assistant message. Oh My Pi's Anthropic converter then inserts a Continue. user message between the two adjacent assistants (providers/anthropic.ts, in the loop that repairs adjacent assistant params). Our check of the prepared turn structure doesn't expect that row, so every pass sees extra rows and refuses the turn.

    We're working on a fix. The check will expect the Continue. row exactly where Oh My Pi inserts one, and keep refusing any other mismatch. I'll post here when it ships.

  2. magic-alfonso commented on Oct 27, 2026

    @magic-alfonso

    Fixed in 0.49.24. Thanks @TheOrdinaryWow for the report and the reproduction.

    When dropping a tool call left two assistant messages next to each other, Oh My Pi inserts its Continue. repair message between them. Magic Context's request check now expects that message, so the turn is no longer refused with comparison=role.

    Update the Pi package and restart Oh My Pi to pick it up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions