Skip to content

vllm_omni.engine.duplex.commands

The command vocabulary one duplex session accepts, plus its mailbox rendering.

DuplexSessionHandle.submit() takes one of these; the websocket handler and InlineDuplexClient build them with :func:command_from_realtime.

The wire half of each command --- which client event it decodes from and what fields survive decoding --- now lives in vllm_omni.protocol.duplex.commands, which carries the whole vocabulary: the eight Tier 1 classes re-exported from vllm_omni.protocol.realtime.commands, the two Tier 2 ones and the seven Tier 3 ones. The engine imports that module and never the Tier 1 one directly, so a command that later grows a duplex extension changes one file (RFC #6592 P0a).

The engine half stays here, because it is not wire contract at all: payload() renders the session-internal mailbox dictionary the runner bodies were written against, and its type is the mailbox channel rather than the client event. Those two genuinely differ --- session.update and conversation.item.create / .delete / .truncate all travel on the turn.signal channel --- which is why the halves are separated instead of the classes being relocated wholesale.

REALTIME_COMMAND_TYPES module-attribute

REALTIME_COMMAND_TYPES: frozenset[str] = frozenset(
    {
        "input_audio_buffer.append",
        "input_audio_buffer.commit",
        "input_audio_buffer.clear",
        "output_audio_buffer.clear",
        "response.create",
        "response.cancel",
        "conversation.item.create",
        "conversation.item.delete",
        "conversation.item.truncate",
        "session.update",
        "playback.ack",
        "session.heartbeat",
        "session.close",
        "turn.signal",
        "input.text.append",
        "input.cancel",
        "barge_in",
    }
)

AckPlayback dataclass

Bases: DuplexCommand, AckPlayback

type class-attribute

type: str = 'playback.ack'

AppendAudio dataclass

Bases: DuplexCommand, AppendAudio

audio class-attribute instance-attribute

audio: bytes = b''

type class-attribute

type: str = 'input_audio_buffer.append'

payload

payload() -> dict[str, object]

AppendText dataclass

Bases: DuplexCommand, AppendText

type class-attribute

type: str = 'input.text.append'

BargeIn dataclass

Bases: DuplexCommand, BargeIn

type class-attribute

type: str = 'barge_in'

CancelInput dataclass

Bases: DuplexCommand, CancelInput

type class-attribute

type: str = 'input.cancel'

CancelResponse dataclass

Bases: DuplexCommand, CancelResponse

type class-attribute

type: str = 'response.cancel'

ClearInput dataclass

Bases: DuplexCommand, ClearInput

type class-attribute

type: str = 'input_audio_buffer.clear'

ClearOutputAudio dataclass

Bases: DuplexCommand, ClearOutputAudio

type class-attribute

type: str = 'output_audio_buffer.clear'

CloseSession dataclass

Bases: DuplexCommand, CloseSession

type class-attribute

type: str = 'session.close'

Commit dataclass

Bases: DuplexCommand, Commit

type class-attribute

type: str = 'input_audio_buffer.commit'

payload

payload() -> dict[str, object]

CreateItem dataclass

Bases: DuplexCommand, CreateItem

type class-attribute

type: str = 'turn.signal'

payload

payload() -> dict[str, object]

CreateResponse dataclass

Bases: DuplexCommand, CreateResponse

type class-attribute

type: str = 'response.create'

payload

payload() -> dict[str, object]

DeleteItem dataclass

Bases: DuplexCommand, DeleteItem

type class-attribute

type: str = 'turn.signal'

payload

payload() -> dict[str, object]

DuplexCommand dataclass

Bases: RealtimeCommand

A Realtime command as the duplex engine handles it.

Adds the mailbox channel (type) and its rendering on top of the wire command; every concrete class below pairs this with its protocol twin.

type class-attribute

type: str = ''

payload

payload() -> dict[str, object]

Render the session-internal mailbox dictionary.

DuplexCommandError

Bases: RealtimeProtocolError

A client payload could not be turned into a duplex command.

The duplex name for a Realtime protocol error: same code / event_id contract, so the error envelope is rendered identically whichever consumer raised it.

Heartbeat dataclass

Bases: DuplexCommand, Heartbeat

type class-attribute

type: str = 'session.heartbeat'

RealtimeCommand dataclass

One decoded OpenAI Realtime client event.

wire_type is the event type the client sent; the typed fields are what survived decoding, so a consumer reads them instead of re-parsing JSON.

There is deliberately no rendering method here. A server receives commands, it does not emit them, and how a runtime represents one internally is its own business --- the duplex engine renders its mailbox dictionary in vllm_omni.engine.duplex.commands.

event_id class-attribute instance-attribute

event_id: str | None = None

wire_type class-attribute

wire_type: str = ''

SignalTurn dataclass

Bases: DuplexCommand, SignalTurn

type class-attribute

type: str = 'turn.signal'

payload

payload() -> dict[str, object]

TruncateItem dataclass

Bases: DuplexCommand, TruncateItem

type class-attribute

type: str = 'turn.signal'

payload

payload() -> dict[str, object]

UpdateSession dataclass

Bases: DuplexCommand, UpdateSession

type class-attribute

type: str = 'turn.signal'

payload

payload() -> dict[str, object]

command_from_realtime

command_from_realtime(
    payload: Mapping[str, object],
    *,
    defaults: RealtimeInputDefaults | None = None,
) -> DuplexCommand

Translate one OpenAI Realtime client event into a command.

Envelope concerns (event_id acknowledgements, resume bookkeeping) are handled by the transport; this function only validates and maps the payload shape. defaults carries the audio format / sample rate / VAD defaults the session declared, so every transport decodes an append the same way. Raises :class:DuplexCommandError for malformed or unsupported payloads.