Skip to main content
A turn-protection window tells the bot gateway to queue new user messages instead of cancelling the running turn, while critical in-flight work — a foreground subagent or context compaction — finishes.

Quick Start

1

Nothing to configure

Foreground subagents and context compaction open the window automatically. Use busy_mode="interrupt" on your bot as before:
Messages that land while a subagent or compaction is running are queued with ”⏳ Finishing current work, your message is queued”.
2

Protect your own code (advanced)

protect_turn(None) is a safe no-op, so the same call works whether or not the agent has an interrupt controller.

How It Works

Once a message is queued, further messages merge into it (MERGED) until it runs, so a later message never drops the queued one. After the queue drains and no window is open, the next mid-run message interrupts as before (INTERRUPTED).

When the window is open

Background subagents (background=True) do not block the parent turn and are not protected.

API


/stop still works inside the window

protect() only affects implicit interrupts — new user messages under busy_mode="interrupt". An explicit /stop, or any call to controller.request(...), still fires immediately:
Protection preserves work when the user is adding information; a stop means the user is withdrawing it.

Best Practices

protect_turn is a safe no-op for None and for custom controllers that do not implement protect(), so code that may run with or without a controller stays simple.
The window delays interrupts. Open it around the specific operation (a subagent run, a compaction) rather than wrapping an entire turn.
request() is not blocked. A stop sent inside the window still fires immediately.

Bot Run Control

busy_mode="interrupt" is the main consumer of the window

Subagent Tool

Foreground subagents open the window automatically

Context Compaction

Compaction opens the window automatically

Cooperative Tool Cancellation

How interrupt_controller and /stop work end-to-end