Skip to content

[pi-plugin] 0.49.0: agent_end after LKG publication still refuses the dispatch ("the run that owned the latest context pass has ended") #673

Closed

Description

@Qiiks

On @cortexkit/pi-magic-context 0.49.0 (the release that closed #667), a user turn still aborts with:

Error: Magic Context could not safely prepare this turn; send your message again.
stage=provider dispatch (origin=agent_end; context stage=LKG/served publication) elapsed=21556ms
recovery=no managed result; refused
(the run that owned the latest context pass has ended; no managed result for this request)

Resubmitting the same message succeeds. Same host, same repo, omp 18.10.3, Linux.

This is not #667

#667 (fixed in 0.49.0) was the superseded path: a late agent_end from an earlier run ending the current pass, or a pass not current at the fence. This is the other guard, which #667 fix does not reach:

  • dist/index.js pi.on("before_provider_request"):
    if (active.ended) {
      refusalOrigin = "agent_end";
      throw new Error("the run that owned the latest context pass has ended; no managed result for this request");
    }
  • The refused message carries context stage=LKG/served publication, i.e. the pass completed and published to LKG before the refusal — the pass was managed and current, then an agent_end (the run ending) set operation.ended = true; operation.ready = false in the agent_end handler between the LKG publication and the run dispatch.

Signature to separate the two: (origin=agent_end; context stage=LKG/served publication) — pass already published, still refused.

Verified in the installed 0.49.0 dist

  • refusalOrigin = "agent_end": exactly 1 occurrence, in before_provider_request.
  • refuse() sets stage to `provider dispatch (origin=${refusalOrigin}; ...)` after the active.ended throw, so the stage text comes from this exact branch.
  • recovery shows no managed result; refused, assigned only in the user-visible arm of refuse() (the !isCurrent() arm returns before assigning it) — so isCurrent() was true; the error reached the user, an agent_end was observed after the pass published.

Occurrences

  • elapsed=6958ms and elapsed=21556ms, distinct turns, both (origin=agent_end; context stage=LKG/served publication) and recovery=no managed result; refused.
  • No provider is dispatched on this path; the refusal happens before any upstream call. A subq/opencode-zen proxy is not involved — no upstream call happens here.

Suggested direction

Constraint to preserve (from magic-alfonso in #667): the fence must only let a provider request through if it is the current run's managed result. In this path the pass is managed and published; agent_end arrives after publication, before dispatch. The fence could treat operation.ended alongside an already-completed, LKG-published pass as "run ended after publish" and dispatch its managed result, instead of refusing. Second candidate: the agent_end handler should not set ended for a pass whose LKG slot was served (published and current), analogous to what #667 changed for the earlier-run case.

Repo: cortexkit/magic-context, packages/pi-plugin. Happy to attach the [magic-context][pi] OMP context counts session=... dispatch_fence=... lines plus the exact events if useful.

Activity

  1. magic-alfonso commented on Oct 13, 2026

    @magic-alfonso

    Thanks for the precise report. The signature you point out (origin=agent_end; context stage=LKG/served publication) is different from issue 667, and the analysis of which branch produced the refusal helps a lot.

    I'm reproducing it on a real Oh My Pi 18.9.x host to see exactly which event ends the run and which request arrives after it. The fix depends on that: the dispatch check has to keep sending only the current run's prepared request, so it can't simply let the published result through without knowing which request it's answering.

    The dispatch_fence=... count lines and the event sequence around one refusal would be useful, if you can share them.

  2. magic-alfonso commented on Oct 14, 2026

    @magic-alfonso

    Fixed in 0.49.1. The dispatch check no longer refuses a prepared turn because of an agent_end that arrives after the last-good request was published. It now matches the outgoing request against the prepared one by structure (message count, roles, tool call ids and the last message), which survives Oh My Pi's own later edits such as secret obfuscation, image compaction and date reminders, so it no longer depends on event timing. Verified on real Oh My Pi 18.10.3 and 18.10.4, including headless chat-completions mode. Update with npx @cortexkit/magic-context@latest setup or by bumping the plugin version, then restart the host.

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