The lifecycle your interface should show

Event or stateWhat it establishesWhat the application should do
response.steer sentThe client asked to add input to an active response on the current WebSocket connection.Store the target response, your change-intent ID, and the exact delta.
response.steer.acceptedThe input is queued. The server may finish the current output item or hosted tool first.Show queued, not applied. Keep listening for the response and steer events.
response.steer.pendingThe model needs application-managed input, such as a function result or approval, before it can continue.Resolve that requirement, then send response.create with the required input and the correct previous_response_id.
response.steer.failedThe queued change failed. The event is tied to the steer ID.Keep the old and new requirements visible, record the error, and decide whether a fresh response is safer than replay.
response completesThe active response ended; it does not by itself prove every requested change was followed.Compare the output and side effects with the revised acceptance checks.

Queued steering exists on the current WebSocket connection and is not stored with the original response. If the connection drops, reconcile the response and tool state before deciding whether to send the change again. Blind replay can duplicate work.

Describe the change as a small delta

Imagine an agent has finished a report and is preparing to email it when the requirement changes: the report should be saved for legal review instead. A compact delta is easier to apply than a rewritten project brief:

PRESERVE: The completed report and its source notes.
STOP: Do not send email or open a compose window.
CHANGE: Replace external delivery with a local review draft.
NEXT: Save the draft in reviews/vendor-north/.
NEED: Report whether any message or external job had already started.

PRESERVE prevents needless rework. STOP governs future action. CHANGE makes the old and new requirements auditable. NEXT gives the model a safe continuation. NEED surfaces consequences the model cannot infer.

Implementation flow

  1. Confirm that the response is still active and that steering is still appropriate. A new outcome, source boundary, or authority model often deserves a fresh response.
  2. Inventory output already shown and every hosted tool, custom function, or external job already queued or started.
  3. Send response.steer on the same WebSocket connection with the active response's previous_response_id and the delta as input.
  4. Record the returned steer ID. Treat response.steer.accepted as an acknowledgement, not a completion receipt.
  5. If response.steer.pending arrives, supply the requested function result or approval through a new response.create continuation. This is the case where another create event is expected.
  6. At the end, reconcile output, tools, approvals, and external side effects against the revised brief.

Minimal steering event

{
  "type": "response.steer",
  "previous_response_id": "resp_123",
  "input": [{
    "role": "user",
    "content": [{
      "type": "input_text",
      "text": "PRESERVE: the report. STOP: external delivery. CHANGE: save a local review draft. NEXT: write the draft. NEED: disclose any action already started."
    }]
  }]
}

The exact client wrapper can differ. Keep protocol details close to the current official documentation and test the event sequence in your own SDK and application.

Handle the three races explicitly

RaceTypical failureUseful safeguard
TextOld wording has already streamed to the user.Preserve it in the audit trail and issue a corrected final handoff; steering cannot retract displayed text.
ToolA hosted tool finishes, or an application job keeps running, before the change applies.Track tool state separately with an idempotency key and real statuses such as started, cancellation requested, canceled, completed, and verified.
ApprovalAn approval remains attached to a target that has changed.Invalidate approval when recipient, target, scope, cost, or irreversible effect changes; ask again with the new target visible.

Test outcomes, not the presence of a steering button

  • Before the current item ends: confirm the change is queued and earlier text remains visible.
  • During a hosted tool: confirm the tool may finish before the new instruction is used.
  • During an application function: provoke response.steer.pending, return the required result, and verify the continuation.
  • Failure: verify response.steer.failed is associated with the correct steer ID and does not silently trigger a replay.
  • Disconnect: reconnect, read actual response and job state, and prevent duplicate side effects.
  • Completion: check that preserved work stayed intact, the obsolete action did not begin, and the revised deliverable exists.

Evidence behind this guide

The protocol description was checked against OpenAI's steering documentation on 2026-09-11. A separate response-only fixture showed that Astra, Sol, and Terra could all follow the preserve/stop/change/next wording when an email step became a local draft. That fixture did not open a WebSocket, emit live steer events, run tools, or test disconnect recovery. Use the downloadable checklist as an implementation aid, then retain your own event log and side-effect evidence.