Skip to content

feat(realtime-api): add Realtime API REST handlers and session registry - #406

Merged
slin1237 merged 1 commit into
mainfrom
yifeliu/realtime-gateway-mod
Mar 4, 2026
Merged

slin1237 merged 1 commit into
mainfrom
yifeliu/realtime-gateway-mod

Conversation

@pallasathena92

@pallasathena92 pallasathena92 commented Feb 11, 2026 •

Copy link
Copy Markdown
Collaborator

openai api spec: https://developers.openai.com/api/reference/resources/realtime
Fix: #240 #241 #242

Description

Problem

The model gateway has no support for OpenAI's Realtime API. Clients that need ephemeral tokens for browser-safe WebSocket or WebRTC authentication (via /v1/realtime/client_secrets, /v1/realtime/sessions, or /v1/realtime/transcription_sessions) cannot route through the gateway, forcing them to connect directly to upstream workers and bypassing the gateway's load balancing, auth, and
circuit-breaker infrastructure.

Additionally, there is no in-memory tracking of active WebSocket sessions or WebRTC calls, which will be needed for upcoming WebSocket/WebRTC proxy phases to manage connection lifecycle, enforce capacity limits, and reap stale entries.

Solution

Introduce the Realtime API module (routers::openai::realtime) with two components:

  1. REST proxy handlers (rest.rs) — three POST endpoints that validate the request body for a model field, select the lowest-load external worker via circuit-breaker-aware routing, forward the request with passthrough auth, record the outcome for circuit breaker health tracking, and proxy the upstream response back to the client.
  2. In-memory session/call registry (registry.rs) — a DashMap-backed, thread-safe registry that tracks WebSocket sessions and WebRTC calls with ConnectionState lifecycle management (Pending → Connected → Disconnected). Uses CAS-based atomic counters for capacity enforcement (default 10k each) and includes a background reaper task that evicts stale non-active entries on a configurable
    interval.

The REST endpoints are wired into the axum router behind the existing auth and concurrency-limit middleware. The registry is created in AppContext and made available through AppState for use by future WebSocket/WebRTC handler phases.

Changes

  • model_gateway/src/routers/openai/realtime/mod.rs (new) — Module declaration exposing registry, rest, and re-exporting RealtimeRegistry.
  • model_gateway/src/routers/openai/realtime/registry.rs (new) — RealtimeRegistry with SessionEntry/CallEntry tracking, ConnectionState enum, atomic capacity enforcement, and a cancellable reaper background task.
  • model_gateway/src/routers/openai/realtime/rest.rs (new) — create_client_secret, create_session, create_transcription_session handlers with shared proxy_realtime_rest logic; select_worker and proxy_response exposed as pub(super) for future sibling modules.
  • model_gateway/src/server.rs — Registers the three realtime REST routes under a new realtime_routes group with auth and concurrency-limit middleware.
  • model_gateway/src/app_context.rs — Adds realtime_registry: Arc to AppContext and initializes it in the builder.
  • model_gateway/src/routers/openai/mod.rs — Declares the new pub mod realtime submodule.
  • model_gateway/src/service_discovery.rs — Adds realtime_registry initialization in test fixture.
  • Cargo.toml (workspace) — Adds tokio-tungstenite and multer workspace dependencies (for upcoming WebSocket/WebRTC phases).
  • model_gateway/Cargo.toml — Adds tokio-util direct dependency for CancellationToken.

Test Plan

Client secret: curl -X POST localhost:30000/v1/realtime/client_secrets -H "Authorization: Bearer $KEY" -d '{"session":{"type":"realtime","model":"gpt-4o-realtime-preview","audio":{"output":{"voice":"alloy"}}}}' → expect client_secret.value + expires_at

curl -X POST http://localhost:30000/v1/realtime/client_secrets \
                -H "Authorization: Bearer $KEY" \
                -H "Content-Type: application/json" \
                -d '{
                  "expires_after": {
                    "anchor": "created_at",
                    "seconds": 600
                  },
                  "session": {
                    "type": "realtime",
                    "model": "gpt-realtime",
                    "instructions": "You are a friendly assistant."}}'
{
  "value": "ek_698ceca6bad481919b5ca42dca20abb7",
  "expires_at": 1770843902,
  "session": {
    "type": "realtime",
    "object": "realtime.session",
    "id": "sess_D8BWgCxbdcPZIZiuA6f5j",
    "model": "gpt-realtime",
    "output_modalities": [
      "audio"
    ],
    "instructions": "You are a friendly assistant.",
    "tools": [],
    "tool_choice": "auto",
    "max_output_tokens": "inf",
    "tracing": null,
    "truncation": "auto",
    "prompt": null,
    "expires_at": 0,
    "audio": {
      "input": {
        "format": {
          "type": "audio/pcm",
          "rate": 24000
        },
        "transcription": null,
        "noise_reduction": null,
        "turn_detection": {
          "type": "server_vad",
          "threshold": 0.5,
          "prefix_padding_ms": 300,
          "silence_duration_ms": 200,
          "idle_timeout_ms": null,
          "create_response": true,
          "interrupt_response": true
        }
      },
      "output": {
        "format": {
          "type": "audio/pcm",
          "rate": 24000
        },
        "voice": "alloy",
        "speed": 1.0
      }
    },
    "include": null
  }
}%                                                                                                                                         

Session creation (legacy): curl -X POST http://localhost:30000/v1/realtime/sessions -H "Authorization: Bearer $KEY" -d '{"model":"gpt-4o-realtime-preview"}' → expect session object with client_secret.value

curl -X POST http://localhost:30000/v1/realtime/sessions \
                -H "Authorization: Bearer $KEY" \
                -H "Content-Type: application/json" \
                -d '{
                  "model": "gpt-realtime",
                  "modalities": ["audio", "text"],
                  "instructions": "You are a friendly assistant."
                }'
{
  "object": "realtime.session",
  "id": "sess_D8BZWy7dupg4uQ7mQZdPf",
  "model": "gpt-realtime",
  "modalities": [
    "audio",
    "text"
  ],
  "instructions": "You are a friendly assistant.",
  "voice": "alloy",
  "output_audio_format": "pcm16",
  "tools": [],
  "tool_choice": "auto",
  "temperature": 0.8,
  "max_response_output_tokens": "inf",
  "turn_detection": {
    "type": "server_vad",
    "threshold": 0.5,
    "prefix_padding_ms": 300,
    "silence_duration_ms": 200,
    "idle_timeout_ms": null,
    "create_response": true,
    "interrupt_response": true
  },
  "speed": 1.0,
  "tracing": null,
  "truncation": "auto",
  "prompt": null,
  "expires_at": 0,
  "input_audio_noise_reduction": null,
  "input_audio_format": "pcm16",
  "input_audio_transcription": null,
  "client_secret": {
    "value": "xxx",
    "expires_at": 1770844078
  },
  "include": null
}%                                     
Checklist
  • cargo +nightly fmt passes
  • cargo clippy --all-targets --all-features -- -D warnings passes
  • (Optional) Documentation updated

Summary by CodeRabbit

  • New Features

    • Added OpenAI Realtime API support with REST endpoints for session creation, client secret management, and transcription sessions
    • Added realtime session and call tracking with connection state awareness and automatic cleanup
  • Chores

    • Workspace updated to include new dependencies required for realtime transports and multipart handling

@github-actions github-actions Bot added dependencies Dependency updates protocols Protocols crate changes model-gateway Model gateway crate changes labels Feb 11, 2026
@coderabbitai

coderabbitai Bot commented Feb 11, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds OpenAI Realtime gateway support: workspace deps (tokio-tungstenite, multer), a DashMap-backed RealtimeRegistry with background reaper, REST token/session endpoints and proxy logic, and integration of realtime registry/routes into AppContext and server routing.

Changes

Cohort / File(s) Summary
Workspace Dependencies
Cargo.toml, model_gateway/Cargo.toml
Added workspace dependencies: tokio-tungstenite = "0.26" (with rustls-tls-native-roots feature) and multer = "3"; added tokio-util as workspace dependency in model_gateway.
App Context & Service Discovery
model_gateway/src/app_context.rs, model_gateway/src/service_discovery.rs
Added realtime_registry: Arc<RealtimeRegistry> to AppContext and initialized it in test setup and builder.
Module Export
model_gateway/src/routers/openai/mod.rs, model_gateway/src/routers/openai/realtime/mod.rs
Exported new realtime module and re-exported RealtimeRegistry; declared registry and rest submodules.
Realtime Registry
model_gateway/src/routers/openai/realtime/registry.rs
New DashMap-backed RealtimeRegistry with SessionEntry/CallEntry, ConnectionState, CRUD APIs, capacity limits, atomic counters, and background reaper that evicts stale/non-connected entries and cancels tokens.
Realtime REST Proxy
model_gateway/src/routers/openai/realtime/rest.rs
Added REST handlers: create_client_secret, create_session, create_transcription_session plus proxying helpers (select_worker, forward_post, proxy_response) handling worker selection, auth, upstream forwarding and response translation.
Server Routing
model_gateway/src/server.rs
Registered realtime REST routes (/v1/realtime/*) with concurrency-limit and auth middlewares and merged them into main Router.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Gateway as Gateway (REST Handler)
    participant Registry as RealtimeRegistry
    participant WorkerMgr as Worker Manager
    participant Upstream as Upstream Service

    Client->>Gateway: POST /v1/realtime/client_secrets (body with model)
    Gateway->>Gateway: extract model & auth
    Gateway->>Registry: (optional) read/write session metadata
    Gateway->>WorkerMgr: select_worker(model)
    WorkerMgr-->>Gateway: Arc<Worker> (or None)
    Gateway->>Upstream: forward POST with auth, headers, body
    Upstream-->>Gateway: Response (status, headers, body)
    Gateway->>Gateway: proxy_response -> build client Response
    Gateway-->>Client: Return upstream status + body
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • CatherineSue
  • key4ng
  • slin1237

Poem

🐰 I dug a hole for realtime play,

Sessions hop in, then drift away,
DashMap guards the carrot trail,
Reaper clears what grows stale,
Tokens bounce and routes relay — hooray! 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR partially addresses issue #240 requirements. It adds tokio-tungstenite and creates the realtime module structure, but does not declare all specified submodules (context, session, tool_handler, upstream, webrtc_handler, websocket_handler) or export all required types and handlers. Either declare all required submodules from #240 even if empty stubs, or update the issue if the scope has been intentionally reduced to REST-only in this phase.
Out of Scope Changes check ⚠️ Warning The PR includes out-of-scope changes beyond #240 objectives: REST handler implementation, registry with DashMap backend, and server route registration were not specified in the linked issue requirements. Either add these implementations to the issue scope documentation, or create separate issues for REST handlers and registry to clarify multi-phase implementation planning.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: adding REST handlers for Realtime API and a session registry.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch yifeliu/realtime-gateway-mod

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @pallasathena92, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly extends the gateway's capabilities by introducing foundational support for OpenAI's Realtime API. It enables clients to generate ephemeral tokens for real-time interactions and establishes an in-memory system for tracking active real-time connections. The changes lay the groundwork for future WebSocket proxy, WebRTC signaling, and MCP interception features, ensuring the gateway can effectively manage and route real-time traffic.

Highlights

  • Realtime API REST Proxy Handlers: Implemented three REST proxy handlers for OpenAI's Realtime API ephemeral token generation: create_client_secret (GA), create_session (legacy), and create_transcription_session (legacy). These handlers select the least-loaded worker supporting the requested model and forward requests, propagating relevant tracing headers.
  • In-Memory Realtime Registry: Introduced a RealtimeRegistry to track WebSocket sessions and WebRTC calls. This registry uses DashMap for storage, enforces capacity limits (10,000 sessions/calls by default), and includes a background reaper task to evict stale or disconnected entries, ensuring efficient resource management.
  • Realtime API Protocol Definitions and Builders: Added comprehensive Rust protocol definitions for OpenAI's Realtime API, covering conversation items, client and server events, response structures, and session configurations. Corresponding fluent builders (RealtimeResponseBuilder, ServerEventBuilder) were also created to simplify the construction of these complex event types.
  • Core Infrastructure Integration: Integrated the new RealtimeRegistry into the AppContext for global access and added the Realtime API routes to the main application router, ensuring these new functionalities are properly exposed and managed within the gateway.
Changelog
  • Cargo.toml
    • Added tokio-tungstenite dependency for WebSocket proxy support.
    • Added multer dependency.
  • model_gateway/Cargo.toml
    • Added tokio-tungstenite and tokio-util workspace dependencies.
  • model_gateway/src/app_context.rs
    • Imported RealtimeRegistry.
    • Added realtime_registry: Arc<RealtimeRegistry> field to AppContext.
    • Initialized realtime_registry with a new instance in AppContextBuilder.
  • model_gateway/src/routers/openai/mod.rs
    • Added pub mod realtime; to expose the new Realtime API module.
  • model_gateway/src/routers/openai/realtime/mod.rs
    • Added new module for OpenAI Realtime API gateway implementation.
    • Declared registry and rest submodules.
    • Re-exported RealtimeRegistry for easier access.
  • model_gateway/src/routers/openai/realtime/registry.rs
    • Added new file defining RealtimeRegistry for in-memory tracking of sessions and calls.
    • Implemented SessionEntry and CallEntry structs with connection states and cancellation tokens.
    • Included methods for registering, retrieving, and removing sessions and calls.
    • Added capacity limits for sessions and calls with warning logs.
    • Implemented a background reaper task to evict stale Pending or Disconnected entries.
  • model_gateway/src/routers/openai/realtime/rest.rs
    • Added new file defining REST handlers for Realtime API token generation endpoints.
    • Implemented create_client_secret for GA ephemeral token generation.
    • Implemented create_session for legacy ephemeral token generation.
    • Implemented create_transcription_session for legacy transcription token generation.
    • Included select_worker helper for worker selection based on model support, circuit breaker, and load.
    • Added forward_post helper to propagate whitelisted headers for trace correlation.
    • Provided proxy_response utility to convert upstream responses to axum responses.
  • model_gateway/src/server.rs
    • Imported realtime::rest module.
    • Defined realtime_routes for /v1/realtime/sessions, /v1/realtime/client_secrets, and /v1/realtime/transcription_sessions.
    • Applied authentication middleware to the realtime_routes.
    • Merged realtime_routes into the main application router.
  • model_gateway/src/service_discovery.rs
    • Initialized realtime_registry in the test AppContextBuilder.
  • protocols/src/builders/mod.rs
    • Added realtime module to the builders.
    • Re-exported RealtimeResponseBuilder and ServerEventBuilder.
  • protocols/src/builders/realtime/mod.rs
    • Added new module for Realtime API builders.
    • Declared response and server_event submodules.
    • Re-exported RealtimeResponseBuilder and ServerEventBuilder and its sub-builders.
  • protocols/src/builders/realtime/response.rs
    • Added new file defining RealtimeResponseBuilder for constructing RealtimeResponse objects with a fluent API.
  • protocols/src/builders/realtime/server_event.rs
    • Added new file defining ServerEventBuilder for constructing hierarchical server-to-client Realtime API events.
    • Implemented nested builders (ResponseEventBuilder, ItemEventBuilder, ContentEventBuilder) for progressive context.
  • protocols/src/lib.rs
    • Added realtime_conversation module.
    • Added realtime_events module.
    • Added realtime_response module.
    • Added realtime_session module.
  • protocols/src/realtime_conversation.rs
    • Added new file defining OpenAI Realtime Conversation API types.
    • Included RealtimeConversationItem enum covering messages, function calls, and MCP interactions.
    • Defined RealtimeContentPart for various content types within messages.
    • Introduced McpListToolEntry and McpCallError for MCP-related types.
  • protocols/src/realtime_events.rs
    • Added new file defining OpenAI Realtime API client and server wire-format event types.
    • Implemented ClientEvent and ServerEvent enums with from_json and to_json methods for robust deserialization.
    • Defined SessionConfig and TranscriptionSessionUpdateConfig unions.
    • Included supporting types like ConversationInfo, ResponseContentPart, LogProb, TranscriptionUsage, TranscriptionError, RateLimitInfo, and RealtimeError.
  • protocols/src/realtime_response.rs
    • Added new file defining OpenAI Realtime API response types.
    • Included RealtimeResponse struct with status, output, metadata, audio, and usage fields.
    • Defined ResponseCreateParams for creating responses.
    • Introduced RealtimeResponseObject, RealtimeResponseStatus, StatusDetailsType, StatusDetailsReason, and ResponseStatusError for response status management.
    • Defined ResponseAudioOutputConfig and ResponseAudioConfig for audio output settings.
    • Included RealtimeUsage and related structs for token usage tracking.
  • protocols/src/realtime_session.rs
    • Added new file defining OpenAI Realtime Session API types.
    • Included RealtimeSessionConfig and RealtimeTranscriptionSessionConfig for session setup.
    • Defined RealtimeAudioFormat, AudioTranscription, NoiseReduction, and TurnDetection for audio processing.
    • Introduced Voice, OutputModality, Tracing, ConnectorId, RealtimeTool, RealtimeToolChoice, MaxOutputTokens, Truncation, and Prompt for comprehensive session configuration.
    • Defined ClientSecret for ephemeral token handling.
Activity
  • The pull request introduces significant new functionality for OpenAI's Realtime API.
  • It includes new Rust modules for API protocol definitions, builders, and gateway handlers.
  • Dependencies tokio-tungstenite and multer were added to support upcoming features.
  • The RealtimeRegistry was created to manage real-time session states and includes a background cleanup task.
  • REST endpoints for ephemeral token generation are now handled by the gateway.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for the OpenAI Realtime API, including REST handlers for ephemeral token generation and an in-memory registry for tracking connections. While the implementation is generally well-structured, there are critical security and reliability concerns: new routes bypass global concurrency limits, and REST handlers lack proper worker load tracking and circuit breaker integration. The session registry reaper also has a potential resource leak for 'Connected' sessions. Further improvements are needed for maintainability and efficiency, specifically addressing code duplication, hardcoded values, and optimizing data access and cleanup in the registry. An unused dependency should also be removed, and Rust use statement conventions should be followed.

Comment thread model_gateway/src/routers/openai/realtime/rest.rs
Comment thread model_gateway/src/routers/openai/realtime/registry.rs Outdated
Comment thread model_gateway/src/server.rs
Comment thread Cargo.toml Outdated
Comment thread model_gateway/src/routers/openai/realtime/rest.rs Outdated
Comment thread model_gateway/src/server.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@model_gateway/src/routers/openai/realtime/registry.rs`:
- Around line 91-116: Existing session/call entries' CancellationToken objects
are never triggered when entries are removed or replaced, causing awaiting tasks
to leak; update register_session and register_call to check for an existing
entry returned by the map insert/replace and call
existing_entry.cancel_token.cancel() before replacing it, and update
remove_session and remove_call (and the reaper eviction logic) to call
entry.cancel_token.cancel() before dropping/removing the entry so any waiting
tasks are signaled; reference the SessionEntry/CallEntry structs' cancel_token
fields and the register_session/register_call/remove_session/remove_call
functions and the reaper eviction code to apply this fix.
- Around line 83-90: The capacity checks for sessions and calls are vulnerable
to TOCTOU races; change register_session (referencing self.sessions and
self.max_sessions) and register_call (referencing self.calls and self.max_calls)
to use an atomic reservation approach instead of checking len() then inserting.
Add an AtomicUsize (e.g., session_count and call_count) or a semaphore to
perform an atomic fetch_add/try_acquire before inserting, only proceed with
inserting into the DashMap if the reservation succeeds, and decrement/release
the counter/semaphore on removal or on insertion failure; alternatively
implement the check-and-insert via DashMap's Entry API combined with an
independent atomic counter so the global limit cannot be exceeded concurrently.
Ensure you update the corresponding cleanup paths to decrement/release the
reservation.

In `@model_gateway/src/server.rs`:
- Around line 616-631: The realtime_routes Router currently only applies
middleware::auth_middleware and thus bypasses the concurrency limiter/queue used
by protected_routes; update realtime_routes to apply the same
concurrency-limiting (and optional wasm) middleware as protected_routes (or
simply merge these routes into protected_routes) so session/token creation is
throttled—specifically, add the same route_layer(s) used by protected_routes to
realtime_routes (the Router named realtime_routes) in addition to
axum::middleware::from_fn_with_state(auth_config.clone(),
middleware::auth_middleware).

In `@protocols/src/realtime_response.rs`:
- Around line 111-128: ResponseStatusError currently only has r#type and code so
the API's "message" is dropped; update the ResponseStatusError struct by adding
a pub message: Option<String> field (keeping serde_with::skip_serializing_none
and the existing derives) so deserialization preserves the error message; ensure
the field name matches the JSON key ("message") and leave
RealtimeResponseStatusDetails unchanged aside from using the updated
ResponseStatusError.
🧹 Nitpick comments (5)
protocols/src/realtime_events.rs (2)

138-146: Consider preserving the original parse error for debugging.

When the initial parse fails, the original error is discarded. This makes debugging difficult when the JSON is valid but doesn't match any known variant. Consider logging or preserving the original error.

♻️ Optional improvement
     pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
         match serde_json::from_str::<ClientEvent>(json) {
             Ok(event) => Ok(event),
-            Err(_) => {
+            Err(e) => {
+                tracing::debug!("Unknown client event, preserving as Unknown: {}", e);
                 let value: serde_json::Value = serde_json::from_str(json)?;
                 Ok(ClientEvent::Unknown(value))
             }
         }
     }

182-186: Fallback mapping for Unknown variant could be misleading.

Mapping ClientEvent::Unknown to RealtimeClientEvent::SessionUpdate as a fallback is documented but could cause subtle bugs if callers forget to check for Unknown first. The comment "callers should check Unknown first" is helpful but easy to miss.

Consider adding a distinct Unknown variant to RealtimeClientEvent if possible, or documenting this more prominently in the method's doc comment.

protocols/src/realtime_session.rs (2)

204-209: Consider documenting variant order for other untagged enums.

Like Voice, these #[serde(untagged)] enums (Tracing, RealtimeToolChoice, MaxOutputTokens, Truncation) rely on variant order for correct deserialization. While the patterns are generally safe (simple type vs object), adding brief comments similar to the Voice enum would improve maintainability.

Also applies to: 323-328, 342-347, 385-390


181-183: Nit: Missing blank line before section comment.

Minor formatting inconsistency - other sections have a blank line before their separator comment.

♻️ Suggested fix
 fn default_output_modalities() -> Vec<OutputModality> {
     vec![OutputModality::Audio]
 }
+
 // ============================================================================
 // Tracing
model_gateway/src/routers/openai/realtime/rest.rs (1)

29-73: Consider extracting shared handler logic to avoid drift.

The three handlers share the same select/auth/forward/proxy flow; a small internal helper could reduce duplication and future divergence.

Comment thread model_gateway/src/routers/openai/realtime/registry.rs Outdated
Comment thread model_gateway/src/routers/openai/realtime/registry.rs
Comment thread model_gateway/src/server.rs Outdated
Comment thread protocols/src/realtime_response.rs
@pallasathena92
pallasathena92 force-pushed the yifeliu/realtime-gateway-mod branch from 796948e to 75fde82 Compare February 11, 2026 23:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@model_gateway/src/routers/openai/realtime/rest.rs`:
- Around line 146-167: The forward_post function sets the worker Authorization
header before copying client headers, allowing a client-supplied "authorization"
to override it; update forward_post (or the header whitelist in
should_forward_request_header) so Authorization cannot be overridden by client
headers — either remove "authorization" from the whitelist in
should_forward_request_header, or move the .header("Authorization", auth) call
in forward_post to after the loop that copies headers (ensuring the worker auth
is set last and cannot be clobbered).

Comment thread model_gateway/src/routers/openai/realtime/rest.rs Outdated
@pallasathena92
pallasathena92 force-pushed the yifeliu/realtime-gateway-mod branch from 75fde82 to 1d1bc7d Compare February 11, 2026 23:52
@pallasathena92 pallasathena92 changed the title feat(realtime api):realtime api client_secrets, ssesion rest api call handler feat(realtime api): add Realtime API REST handlers and session registry Feb 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@model_gateway/Cargo.toml`:
- Around line 114-115: Update the workspace Tokio dependency to at least 1.42.1
to address the broadcast-channel unsoundness (RUSTSEC-2025-0023): modify the
workspace Cargo.toml Tokio version entry (the one referenced by
tokio-tungstenite and tokio-util) to >=1.42.1, run cargo update and cargo test;
additionally audit code that handles tungstenite::Message payloads (places using
tokio-tungstenite 0.26, functions/methods that match or construct Message
variants) and change handling from Vec<u8>/String to the new Bytes/Utf8Bytes
types (adjust pattern matches, conversions, and any usages of
Message::Text/Message::Binary accordingly).

In `@model_gateway/src/routers/openai/realtime/registry.rs`:
- Around line 211-287: The reaper in start_reaper currently evicts any entry
older than max_age and deducts counters using the stale_id list lengths, which
can remove active sessions and cause underflow if concurrent deletions occur;
update the logic to (1) when building stale_session_ids/stale_call_ids only
consider entries whose state is not the active/connected state (e.g., check
entry.state != SessionState::Connected or the equivalent enum variant used in
your code), and (2) instead of using
stale_session_ids.len()/stale_call_ids.len() to adjust session_count/call_count,
increase a local removed_sessions/removed_calls counter only when
registry.sessions.remove(id) / registry.calls.remove(id) returns Some and then
subtract that actual removed count (or clamp to current value) from
session_count/call_count to avoid underflow. Ensure you reference start_reaper,
registry.sessions, registry.calls, entry.state, entry.cancel_token,
session_count and call_count when making the changes.

Comment thread model_gateway/Cargo.toml Outdated
Comment thread model_gateway/src/routers/openai/realtime/registry.rs
@CatherineSue CatherineSue added realtime-api Realtime API related changes openai OpenAI router changes labels Feb 13, 2026
@pallasathena92 pallasathena92 changed the title feat(realtime api): add Realtime API REST handlers and session registry feat(realtime-api): add Realtime API REST handlers and session registry Mar 4, 2026
@mergify

mergify Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Hi @pallasathena92, this PR has merge conflicts that must be resolved before it can be merged. Please rebase your branch:

git fetch origin main
git rebase origin/main
# resolve any conflicts, then:
git push --force-with-lease

@mergify mergify Bot added the needs-rebase PR has merge conflicts that need to be resolved label Mar 4, 2026
@pallasathena92
pallasathena92 force-pushed the yifeliu/realtime-gateway-mod branch from 1d1bc7d to 3e342ce Compare March 4, 2026 00:45
@github-actions github-actions Bot removed the protocols Protocols crate changes label Mar 4, 2026
@mergify mergify Bot removed the needs-rebase PR has merge conflicts that need to be resolved label Mar 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@model_gateway/src/app_context.rs`:
- Line 305: RealtimeRegistry is instantiated with hardcoded defaults via
RealtimeRegistry::new(), so make its capacity configurable by constructing it
from the RouterConfig (or via a builder) instead of new(); replace the
Arc::new(RealtimeRegistry::new()) at realtime_registry with a call that consumes
limits from RouterConfig (e.g., RealtimeRegistry::from_config(...) or
RealtimeRegistry::with_limits(...)) or inject a prebuilt RealtimeRegistry from
the context builder so session/call caps come from RouterConfig and not a fixed
default.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d1bc7d and 3e342ce.

📒 Files selected for processing (3)
  • Cargo.toml
  • model_gateway/Cargo.toml
  • model_gateway/src/app_context.rs

Comment thread model_gateway/src/app_context.rs
@pallasathena92
pallasathena92 force-pushed the yifeliu/realtime-gateway-mod branch from 3e342ce to 8be8a08 Compare March 4, 2026 01:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@model_gateway/src/routers/openai/realtime/registry.rs`:
- Around line 254-287: The reaper currently snapshots
stale_session_ids/stale_call_ids and then removes by key, which can evict a
newly re-registered entry with the same id; instead, when iterating ids (or when
attempting removal) perform the staleness check inside the same critical section
before canceling/removing: for registry.sessions and registry.calls, replace the
two-phase snapshot/remove with a per-key remove-attempt that locks/queries the
entry and checks entry.state != ConnectionState::Connected &&
now.duration_since(entry.created_at) > max_age immediately before calling
registry.sessions.remove(id)/registry.calls.remove(id) and
entry.cancel_token.cancel(), so only entries that are still stale at removal
time are canceled and counted (update uses of stale_session_ids/stale_call_ids,
sessions_reaped, calls_reaped accordingly).
- Around line 53-55: The module relies on atomic counters and DashMap operations
to keep capacity counters consistent with map membership; add explicit
INVARIANT: comments at each reservation and removal site (e.g., the code paths
that increment/decrement the atomic capacity counters and the DashMap
insert/remove calls) stating the expected relationship between the counter and
map (for example, "INVARIANT: counter == number of entries in DASH_MAP for this
shard/tenant" and "INVARIANT: any increment must be paired with a subsequent
DashMap::insert on success; any decrement only after DashMap::remove
failed/rolled-back"). Place these INVARIANT: markers adjacent to the reservation
function(s) and removal/rollback function(s) so future reviewers can audit the
atomic counter ↔ DashMap consistency assumptions; continue to reserve SAFETY:
only for unsafe soundness explanations.

In `@model_gateway/src/routers/openai/realtime/rest.rs`:
- Around line 144-154: The forward_post function currently only sets
Authorization and JSON body but must also forward whitelisted trace headers for
propagation; update the signature of forward_post to accept a headers
map/Reference (e.g., &http::HeaderMap or &HeaderMap) and inside forward_post
copy the specific headers "x-request-id", "traceparent", "tracestate", and
"x-correlation-id" from that headers collection onto the reqwest::RequestBuilder
(using .header(...) only when the header exists), then update the call site that
invokes forward_post (where headers is available) to pass the headers argument
so the upstream receives the trace headers.
- Around line 173-189: In proxy_response, only Content-Type is forwarded which
loses useful upstream headers; update proxy_response(resp: reqwest::Response) to
copy a safe whitelist of upstream headers (e.g. "x-request-id", any
"x-ratelimit-*" matches, "retry-after") from resp.headers() into the outgoing
response headers while explicitly excluding hop-by-hop and sensitive headers, or
alternatively document that header propagation is intentionally disallowed;
locate and modify the headers construction around the match on
resp.bytes().await to build the response header list from the filtered
resp.headers() rather than the current single content-type entry.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e342ce and 8be8a08.

📒 Files selected for processing (9)
  • Cargo.toml
  • model_gateway/Cargo.toml
  • model_gateway/src/app_context.rs
  • model_gateway/src/routers/openai/mod.rs
  • model_gateway/src/routers/openai/realtime/mod.rs
  • model_gateway/src/routers/openai/realtime/registry.rs
  • model_gateway/src/routers/openai/realtime/rest.rs
  • model_gateway/src/server.rs
  • model_gateway/src/service_discovery.rs

Comment thread model_gateway/src/routers/openai/realtime/registry.rs
Comment thread model_gateway/src/routers/openai/realtime/registry.rs
Comment thread model_gateway/src/routers/openai/realtime/rest.rs
Comment thread model_gateway/src/routers/openai/realtime/rest.rs
@pallasathena92
pallasathena92 force-pushed the yifeliu/realtime-gateway-mod branch from 8be8a08 to d9d2efa Compare March 4, 2026 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Dependency updates model-gateway Model gateway crate changes openai OpenAI router changes realtime-api Realtime API related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Realtime Api] gateway-realtime-mod

3 participants