fix(router): resolve realtime session model to routed deployment - #36811
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Greptile SummaryThe PR synchronizes a realtime session model with the deployment selected by the router while preserving sessions without a model and nested transcription configuration
Confidence Score: 5/5The PR appears safe to merge No blocking failure remains
|
| Filename | Overview |
|---|---|
| litellm/router.py | Validates session mappings and replaces an existing session model with the selected deployment model |
| tests/test_litellm/test_router.py | Adds regression coverage for model resolution, nested transcription preservation, and sessions without models |
Reviews (2): Last reviewed commit: "chore: merge litellm_internal_staging in..." | Re-trigger Greptile
| """ | ||
| captured: dict = {} | ||
|
|
||
| async def capture_kwargs(**kwargs): |
There was a problem hiding this comment.
Both new tests mutate coarse dict capture state through untyped callbacks, weakening type discipline and making request assertions less explicit
Context Used: CLAUDE.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…ssion_model Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
|
…ssion_model Carries a mutable-ok suppression on the router session rewrite for the tightened LIT002 budget, since the realtime callees deep-copy and JSON-dump the session, and captures the realtime session kwargs through an async mock in the router tests instead of an untyped dict.
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit ec1fba5. Configure here.
719b671
into
litellm_internal_staging
TLDR
Problem this solves:
session/v1/realtime/callssends another, OpenAI rejects the callHow it solves it:
session.modelto the routed deploymentUser Flow
Before: a developer whose voice app mints ephemeral realtime keys through the gateway cannot connect a WebRTC call on any model group whose name differs from the underlying model
openai/openai/gpt-realtime-2.1-minibacked byopenai/gpt-realtime-2.1-mini{"session": {"type": "realtime", "model": "openai/openai/gpt-realtime-2.1-mini"}}value, butsession.modelreadsopenai/gpt-realtime-2.1-mini, the group name minus one prefix rather than the deployment's own modelModel "gpt-realtime-2.1-mini" does not match the realtime token model., so the call never connectsmy-realtimefails one step earlier: step 2 returns HTTP 400LLM Provider NOT provided ... You passed model=my-realtimeAfter: the same two requests connect the call
openai/openai/gpt-realtime-2.1-minibacked byopenai/gpt-realtime-2.1-mini{"session": {"type": "realtime", "model": "openai/openai/gpt-realtime-2.1-mini"}}valueandsession.modelreadinggpt-realtime-2.1-mini, the deployment's own modelmy-realtimemints and connects the same wayRelevant issues
Fixes #36742
Linear ticket
Resolves LIT-6677
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Live proxy against real OpenAI; every 200 and 201 below mints or connects a real realtime session and costs real money. Both legs run the same topology: two proxy instances per leg, each booted with
--num_workers 2, the key minted on instance A and the call placed through instance B, so the ephemeral token has to survive a hop between pods that share nothing but the configConfig served on both legs:
Launcher, run once per instance on its own free random port:
offer.sdpis a real audiosendrecvoffer generated with aiortc'sRTCPeerConnection.ws_probe.pyopens/v1/realtime?model=...with thewebsocketslibrary, sends nothing, and prints the first server event'stypeandsession.model.EPHEMERALis thevaluereturned by the mint step right above each callBefore (ba2e5d2)
Provider-prefixed alias
openai/openai/gpt-realtime-2.1-miniMint the ephemeral key on instance A
Place the WebRTC call on instance B with that key
Plain alias
my-realtimeMint the ephemeral key on instance A
Non-aliased group
gpt-realtime-2.1-miniMint the ephemeral key on instance A
Place the WebRTC call on instance B with that key
Websocket
/v1/realtimeon both instancesOpen the websocket and read the first event
python ws_probe.py ws://localhost:36020/v1/realtime?model=openai/openai/gpt-realtime-2.1-mini sk-lit6677Open the websocket and read the first event
python ws_probe.py ws://localhost:36020/v1/realtime?model=my-realtime sk-lit6677Open the websocket and read the first event
python ws_probe.py ws://localhost:24545/v1/realtime?model=openai/openai/gpt-realtime-2.1-mini sk-lit6677Open the websocket and read the first event
python ws_probe.py ws://localhost:24545/v1/realtime?model=my-realtime sk-lit6677After (ec1fba5)
Provider-prefixed alias
openai/openai/gpt-realtime-2.1-miniMint the ephemeral key on instance A
Place the WebRTC call on instance B with that key
Plain alias
my-realtimeMint the ephemeral key on instance A
Place the WebRTC call on instance B with that key
Non-aliased group
gpt-realtime-2.1-miniMint the ephemeral key on instance A
Place the WebRTC call on instance B with that key
Websocket
/v1/realtimeon both instancesOpen the websocket and read the first event
python ws_probe.py ws://localhost:48795/v1/realtime?model=openai/openai/gpt-realtime-2.1-mini sk-lit6677Open the websocket and read the first event
python ws_probe.py ws://localhost:48795/v1/realtime?model=my-realtime sk-lit6677Open the websocket and read the first event
python ws_probe.py ws://localhost:38771/v1/realtime?model=openai/openai/gpt-realtime-2.1-mini sk-lit6677Open the websocket and read the first event
python ws_probe.py ws://localhost:38771/v1/realtime?model=my-realtime sk-lit6677Observations from the run:
gpt-realtime-2.1-miniworked on both legs; left aloneType
🐛 Bug Fix
Caveats (if any)
Low
/openai/v1/realtime/client_secretspasses through untouched; it rejects a top-levelmodelbefore and aftersessionkwarg carrying amodelkey gets the same rewrite; today only the two realtime entry points pass onelogging_testingis red ontest_bedrock_kb_request_body_has_transformed_filtersat the merge base too (staging PR fix(vector_stores): s3 vectors search router bypass + rag query config drop + ui error swallow #34788 added arouterkwarg the test fake does not accept); it is not a required check and is unrelated to this changeFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/17272f72fa994ee0903d2de98ccb5874
Open in Devin Desktop: https://app.devin.ai/desktop/session/17272f72fa994ee0903d2de98ccb5874?variant=devin