Skip to content

[Feature]: Steering message support — inject user messages into running agent turns #844

@Anis-agent

Description

@Anis-agent

Problem

OpenAB currently processes messages in a strictly turn-based manner:

  1. User sends a message → agent begins execution (potentially a long tool chain)
  2. User sends a follow-up message mid-execution to redirect the agent
  3. The new message is buffered until the agent's current turn completes
  4. Agent finishes going in the wrong direction, then sees the correction — wasting time and tokens

This creates a fundamental capability regression: every major agentic client (Claude Code terminal, GitHub Copilot, Codex, Kiro CLI, Cursor) supports mid-execution steering natively. Routing through OpenAB's broker silently downgrades that capability.

Current Behavior

Any message sent while an agent session is busy is enqueued and delivered only after the current turn boundary. There is no way to interrupt or redirect a running agent without waiting for it to finish.

Expected Behavior

Messages marked as steering messages are injected directly into the agent's current turn via stdin, allowing the agent to adjust its direction immediately — without waiting for the turn to complete.

Non-steering messages continue to use the existing queue behavior (no breaking change).

Industry Precedent

GitHub Copilot SDK

The Copilot SDK explicitly distinguishes between two modes:

  • Steering: message is injected into the agent's active turn; agent sees it immediately
  • Queueing: message is buffered to the next turn (FIFO, existing behavior)

CLI-based agents

Agent Mid-turn steering
Claude Code (terminal) ✅ Type at any time
GitHub Copilot CLI ✅ Steering + queueing modes
Codex ✅ Supports mid-run input
Kiro CLI ✅ Supports mid-turn user input
Cursor ✅ Interrupt + redirect

OpenAB is the only layer in the stack that removes this capability.

Proposed Solution

Prefix-based steering (recommended)

Users mark a message as a steering message using a configurable prefix:

!! stop — use the staging environment, not production

or using a slash command alias:

/steer revert that last file change, use the functional approach instead

OpenAB detects the prefix → writes directly to the agent's stdin → agent receives it immediately within the current turn.

Flow: Steering vs Queueing

User message arrives
        │
        ▼
Is agent session busy?
   │              │
  NO             YES
   │              │
   ▼              ▼
Normal        Has steering prefix?
dispatch        │              │
               YES             NO
                │               │
                ▼               ▼
           Inject to        Buffer to
           agent stdin      next turn
           (steering)       (queueing)
                │               │
                ▼               ▼
         Agent adjusts    Existing behavior
         immediately      (no change)

Config

[steering]
enabled  = true
prefix   = "!!"                # trigger prefix
mode     = "prefix"            # "off" | "prefix" | "implicit"
fallback = "queue"             # if agent doesn't support mid-turn stdin: "queue" | "drop" | "error"

Modes:

Mode Behaviour
off Feature disabled; all messages queue (current default)
prefix Only messages starting with the configured prefix are steered
implicit Any message sent while agent is busy is treated as steering (opt-in)

Alternatives Considered

Implicit steering (all busy-time messages)

Automatically treat every message sent during agent execution as a steering message. Simpler UX but risks unintentional interruption. Recommended only as an opt-in mode = "implicit" setting.

Reaction-based steering

User adds a specific emoji reaction (e.g. ⚡) to their own message → OpenAB promotes it to a steering inject. Works well for platforms with rich reaction support (Discord, Slack) but creates inconsistency across channels (Gateway, Telegram).

ACP protocol extension

Extend the ACP message schema to carry a steering: true flag. More principled but requires coordinated changes across all ACP-compatible agents. Scope is too large for an initial implementation; better as a follow-up once broker-side steering is validated.

Impact

Dimension Without steering With steering
Wasted tokens High — agent completes wrong work Low — agent corrects mid-turn
Wasted time Full turn duration Near-zero
Safety No mid-turn abort path User can steer agent away from risky actions
UX parity Below terminal clients On par with terminal clients

Scope

  • Affects all channel adapters: Discord, Slack, Gateway, Telegram
  • No ACP protocol changes required for initial implementation
  • Graceful fallback if underlying agent binary does not support mid-turn stdin input
  • Race condition handling needed: steering message arriving as agent completes its turn

Environment

  • All platforms (Discord, Slack, Gateway, Telegram)
  • All ACP-compatible agent binaries

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    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