Skip to content

Rethink mid-turn interrupt-steering for passive vs explicit messages #603

@dcramer

Description

@dcramer

Mid-turn steering currently treats all injected messages the same way regardless of how they arrived in the thread. This causes two distinct problems: passive ambient messages incorrectly redirect an in-progress agent turn, and explicit messages that correctly trigger steering sometimes cause the agent to lose its prior loaded context.

Current behavior

  • When a new Slack message arrives while a turn is running, it is queued as a potential steering message.
  • At each tool boundary (prepareNextTurn), drainSteeringMessages calls decideSubscribedReply — the same classifier used for regular subscribed-thread replies — on every queued message.
  • Messages classified shouldReply: true are converted to plain Pi user messages and injected via agent.steer() under steeringMode: "all" (respond.ts:1379).
  • Explicit @-mention messages fast-path to shouldReply: true (subscribed-decision.ts, ExplicitMention branch) without considering turn state.

Problem 1 — Passive messages causing interrupt-steering

The subscribed reply classifier has false-positive rate acceptable for starting new turns but too high for mid-turn injection. Side conversations and ambient team chatter that share topic vocabulary with the active task can score above threshold. Once accepted, the message is injected with no further gate; steeringMode: "all" means the agent acts on it. The result is the agent being pulled off-task by messages never intended for it.

Problem 2 — Explicit steering drops prior instruction context

Explicit mentions correctly trigger steering, but the injected message is a bare user Pi turn appended to an in-progress tool-call sequence. Skill instructions are dynamically loaded content in that sequence (not part of the system prompt), so a new user directive mid-turn can cause the model to treat it as a clean redirect and lose skill context already established by earlier tool results.

Gap

  • Passive messages should never cause steering; the classifier gate for mid-turn injection needs a higher bar or a separate signal (e.g., only isExplicitMention allows steering).
  • Explicit steering messages should carry a context reminder that keeps the prior instruction chain intact — either a synthetic system note or an explicit "continue previous task" wrapper.
  • The two failure modes warrant separate fixes: one is a routing/gate problem, the other is a context-continuity problem.

Affected files

  • packages/junior/src/chat/respond.tsdrainSteeringMessages, steeringMode: "all" at line 1379
  • packages/junior/src/chat/runtime/slack-runtime.tsselectAcceptedSteeringMessages, decideSteeringMessage
  • packages/junior/src/chat/services/subscribed-decision.ts — shared classifier, no steering-specific path

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions