Skip to content

[FEATURE]: conditional steering admission with an expected-turn guard #58776

Closed as not planned

Description

@dominicarrojado

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

Please consider optional conditional steering admission: admit a correction only if the Session still owns the turn/context shown when a plugin offered its steering control.

The consumer is a Telegram bridge. Its busy notice offers a correction to the current turn, while ordinary queue and abort controls remain separate. A native busy query followed by prompt submission cannot enforce the notice's stale-turn rejection guarantee.

Reproduction

  1. Read a busy Session's current user message and agent/model/thinking variant.
  2. Before the correction is persisted, another Desktop prompt changes the Session context, or interruption/completion invalidates the original turn.
  3. Submit the correction using the saved context.
  4. The request is accepted instead of reporting that the displayed turn changed. In the legacy noReply path it can also restore the old agent/model settings.

On v1.19.4, a native SDK probe verified ordinary steering during a running tool call. A separate deterministic mocked persistence interleaving reproduced the stale acceptance; this is not a claim that a native concurrency regression has already been run.

Requested contract

  • Obtain an authoritative Session/turn-context guard, then compare it atomically with admission under the native owner that coordinates competing prompts, interruption, completion, and context changes.
  • Reject an invalidated guard with a typed conflict, without appending input/messages, changing context or permissions, or starting execution. A last-user-message ID alone must not survive an abort/resume or owner replacement incorrectly.
  • Return the accepted native input identity and retain exact-request reconciliation without creating duplicate input. Existing unconditional prompt behavior stays unchanged.

The intended concurrency rule is simple: invalidation wins and steering is rejected, or steering admission wins and later actions retain their normal semantics. This does not promise interruption of an already-running tool.

Existing implementation and related work

The legacy prompt path persists before returning for noReply. Current Session admission supports durable steering but has no expected-turn input in the inspected request contract.

Related #56115 deliberately separates conditional admission from exposing busy snapshots and inbox cancellation. This request is for that stronger admission guarantee, not another busy-query API.

I am seeking design review before implementation: should this extend the current Session admission contract and plugin host surface, and is support planned only for the newer API or also for the legacy surface used by installed Desktop plugins? The downstream target is a standard supported Desktop release rather than a permanent custom build.

Activity

  1. opencode-agent commented on Oct 24, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed write-up and the design notes.

    To restate the request: you'd like an optional guard on steering admission. A correction would be admitted only if the Session still owns the turn and context the caller saw (user message, agent/model/variant). If a newer prompt, an abort or completion has invalidated that turn, the request would be rejected with a typed conflict and nothing would change. Plain prompts would keep working as they do now.

    On your scope questions:

    • v2: in the current code, Session.prompt reconciles by message ID and then admits, and there is no expected-turn input. A plugin can't make a busy check and a submit atomic, so this would need a core change, with the guard compared in the same step as admission, plus a way to expose it on the plugin host ctx.session surface. Maintainers will consider it; I can't promise anything about whether or when.
    • v1 (the legacy noReply path): v1 only receives critical fixes, so a new contract there is unlikely. Any work on this would be for v2.

    Related:

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