Skip to content

Realtime Client

Package: main_logic/omni_realtime_client/

OmniRealtimeClient owns the native-audio conversation path selected by LLMSessionManager for audio input. The class is assembled from transport, response, audio, media/Gemini, and tool mixins behind the stable main_logic.omni_realtime_client import.

Provider transports

Provider routeTransport behavior
QwenDashScope realtime WebSocket events
OpenAI / GPTOpenAI realtime WebSocket events; uplink audio is converted to 24 kHz
StepStep realtime WebSocket events
GLMZhipu realtime WebSocket events
GrokRealtime WebSocket event path
GeminiGoogle GenAI SDK live session, not the raw WebSocket implementation
Free routeEndpoint-dependent: Gemini-proxy/live-stream or Step-compatible behavior

The client selects one branch from api_type, model, and endpoint configuration. A connection failure is surfaced to the session manager; it does not silently create an OmniOfflineClient.

Public lifecycle

MethodContract
connect(instructions, ...)Open the selected provider session and configure turn detection, audio, tools, and instructions
handle_messages()Run the receive loop for WebSocket transports
update_session(config)Send provider-specific session updates
stream_audio(audio_chunk)Process and upload one PCM input chunk
stream_image(image_b64, bypass_rate_limit=False)Send or analyze one visual frame
prime_context(text, skipped=False)Seed startup/hot-swap context using provider-specific semantics
create_response(instructions, skipped=False)Add a user item and request a response
inject_text_and_request_response(text, on_rejected=None)Perform the proactive text-injection/response operation atomically
prompt_ephemeral(...)Request a temporary proactive response
cancel_response() / handle_interruption()Cancel or truncate the active provider response where supported
close()Stop background tasks, close the live transport, and release media/tool state

Callbacks include streamed text and audio, input/output transcripts, response completion, tool calls, status, and connection errors. Interruption is handled through the lifecycle methods; there is no universal constructor-level on_interrupt event contract for this client.

Audio and turn detection

The client accepts PCM bytes without a sample-rate argument and distinguishes the two capture formats used by the application:

  • 480-sample / 960-byte PC chunks arrive at 48 kHz, pass through the RNNoise path, and are downsampled to the internal 16 kHz stream;
  • 512-sample / 1024-byte mobile chunks are already 16 kHz and bypass PC denoising;
  • OpenAI realtime upload is resampled from the internal stream to 24 kHz at the final send step.

TurnDetectionMode.SERVER_VAD is the default, but server VAD is not available on every route. Gemini, the free Gemini proxy, livestream, and explicit manual modes use client-side turn handling. The local fallback prefers RNNoise VAD when available and otherwise uses RMS-based speech detection with sustain/grace timing.

Images

Qwen, GLM, GPT, Gemini, and the compatible free Gemini route can receive native visual frames. Other realtime models use the separately configured vision model to turn the first relevant frame into text context.

Native frames are throttled by NATIVE_IMAGE_MIN_INTERVAL (1.5 seconds). Idle capture multiplies the interval by IMAGE_IDLE_RATE_MULTIPLIER (5). bypass_rate_limit=True is reserved for a deliberate one-shot cue such as a proactive screenshot.

Tools and proactive injection

Tool definitions are normalized once and encoded into the selected provider's supported wire format. Results are returned with provider-specific events. A bounded sliding-window guard prevents a realtime tool-call flood.

inject_text_and_request_response() is used by proactive callbacks that must speak immediately. It rejects or requeues work if another response owns the session rather than interleaving two response streams.

Concurrency, backpressure, and failures

Audio and image processing have dedicated async locks. Sends are bounded by a semaphore, and fire-and-forget work is tracked so close() can cancel it. HTTP/WebSocket 503 responses trigger a short send throttle; fatal frame, timeout, and transport failures notify the connection-error callback and close the session.

These mechanisms protect one live provider connection. Provider failover and switching between text and audio clients remain session-manager responsibilities.