Skip to content

Offline Client

Package: main_logic/omni_offline_client/

OmniOfflineClient is the streamed chat-completion client used by text-input sessions. LLMSessionManager selects it explicitly when input_mode == "text"; it is not an automatic fallback after a realtime connection fails.

The public class is composed from lifecycle, streaming, media, tool, and Gemini-support mixins. main_logic.omni_offline_client remains the stable import path.

Request model

connect(instructions) initializes the in-memory system message and client state. It does not open a persistent model socket. Each stream_text() call performs an async streamed request, emits callbacks, and then updates conversation history.

The main lifecycle methods are:

MethodContract
connect(instructions, native_audio=False)Initialize the system prompt and history
stream_text(text)Send a user turn, stream visible text, and persist the completed turn
stream_image(image_b64)Stage an image for the next text turn
switch_model(model, use_vision_config=False)Replace the chat client under an async model-switch lock
prime_context(text, skipped=False)Append startup/hot-swap context to the system message
create_response(instructions, skipped=False)Append a persistent user message; retained as the realtime-compatible interface
prompt_ephemeral(...)Run a temporary instruction without persisting that instruction
cancel_response() / handle_interruption()Stop accepting chunks from the active response
close()Close HTTP/SDK clients and clear history and staged media

stream_audio() and send_event() are compatibility no-ops. Text mode does not perform STT inside this client.

Providers and multimodal input

The normal path uses the project's chat-LLM adapter for configured OpenAI- and Anthropic-compatible providers. Eligible native Gemini configurations use the Google GenAI SDK path instead. Provider compatibility depends on the adapter and configured endpoint; it is not guaranteed for every arbitrary OpenAI-shaped server.

The client is not text-only. stream_image() queues base64 images, and the next stream_text() builds a multimodal user message. A separately configured vision model and endpoint can be selected when images are present. Old image payloads are evicted from retained history to limit growth.

External speech synthesis is owned by LLMSessionManager and the TTS client, not by OmniOfflineClient.

Tool calls

set_tools(), set_tool_call_handler(), and has_tools() manage the current tool contract. Tool-aware streaming supports the compatible chat formats and the native Gemini SDK format, validates tool calls, invokes the manager callback, and feeds results back to the model. max_tool_iterations bounds repeated model/tool cycles and defaults to three.

Async and cancellation boundaries

  • Streaming and lifecycle methods are async; model replacement is serialized by _model_switch_lock.
  • Conversation history belongs to one client instance. Parallel user turns are not a supported way to mutate it.
  • cancel_response() changes the response state so later chunks are discarded. It does not promise transport-level cancellation of every provider request already in flight.
  • close() also offloads the synchronous Gemini SDK close operation so it does not block the event loop.

Retry and failure behavior

Normal text streaming retries retryable model/network errors up to three total attempts with short backoff. A close or interruption stops further attempts. Account, API-key, quota, safety, empty-completion, repetition, and response-length conditions have separate status/discard callbacks so the manager can surface or recover from them.

If construction, model switching, or all retries fail, the error is reported through callbacks or raised to the session layer. The client does not switch itself to OmniRealtimeClient or to another provider.