fix(bedrock): emit Nova Sonic realtime session.created on connect and session.updated on session.update - #34133
Conversation
Greptile SummaryThis PR completes the Nova Sonic realtime session lifecycle. The main changes are:
Confidence Score: 5/5This looks safe to merge.
|
| Filename | Overview |
|---|---|
| litellm/llms/bedrock/realtime/handler.py | Adds connection-time session creation and client update acknowledgements. |
| litellm/llms/bedrock/realtime/transformation.py | Centralizes session event construction and suppresses duplicate creation events. |
| pyproject.toml | Declares the Bedrock realtime SDK as a Python 3.12+ optional dependency. |
| uv.lock | Adds the Bedrock realtime dependency and its resolved package graph. |
| tests/test_litellm/llms/bedrock/realtime/test_bedrock_realtime_handler.py | Adds tests for connection and session-update lifecycle events. |
| tests/test_litellm/llms/bedrock/realtime/test_bedrock_realtime_transformation.py | Adds session event shape tests and verifies duplicate suppression. |
Reviews (2): Last reviewed commit: "fix(bedrock): emit realtime session.crea..." | Re-trigger Greptile
…dated on session.update Nova Sonic realtime over /v1/realtime never sent session.created unprompted on connect, so OpenAI-Realtime-conformant clients that wait for it before sending session.update deadlocked: the client waited on the server, the client-to-Bedrock loop waited on the client, and Bedrock waited on litellm. The handler now emits a synthesized session.created immediately after the bidirectional stream is established, and session.updated when the client sends session.update. Also declares the aws-sdk-bedrock-runtime dependency (the experimental SDK the realtime handler lazily imports for InvokeModelWithBidirectionalStream, which boto3 cannot do) as a pinned bedrock-realtime optional extra, so a stock install no longer fails with ImportError.
6d7d03d to
973bad7
Compare
|
@greptileai pushed a follow-up addressing both findings: the session.updated ack now reflects the client's requested modalities, and the reactive Bedrock sessionStart no longer forwards a duplicate session.created (single-source on connect). Also regenerated uv.lock for the new bedrock-realtime extra |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…tellm_bedrock_nova_realtime_session_created # Conflicts: # uv.lock
… ruff strict gate Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
Mubashir Osmani seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
f1f0a0b
into
litellm_internal_staging
Relevant issues
Linear ticket
Resolves LIT-4655
fixes a failing e2e test - https://github.com/BerriAI/litellm/blob/litellm_internal_staging/tests/e2e/llm_translation/realtime/test_nova_sonic_realtime_e2e.py
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Live, against real AWS Bedrock
bedrock/amazon.nova-sonic-v1:0(mode: realtime), no mocks. The client follows the OpenAI Realtime protocol: it waits forsession.createdbefore sending anything.Config (
nova_realtime_only.yaml):Launch (needs
aws-sdk-bedrock-runtimeinstalled, i.e.pip install 'litellm[bedrock-realtime]'):Probe client (waits for
session.createdfirst, thensession.update->conversation.item.create->response.create, logs every event type):Before (shipping code, base
7015bd2ea1)The server never emits
session.createdon connect, so the probe blocks forever on its firstrecv():Proxy side showed the socket was accepted but nothing was ever sent back:
After (this PR,
6d7d03d194)session.createdarrives unprompted on connect,session.updatedacks the client'ssession.update, and the full realtime turn completes throughresponse.done.Type
🐛 Bug Fix
Changes
PR #31924 (LIT-2239) fixed a different Nova Sonic realtime hang, the
response.createno-op and the missingresponse.done, but left a second protocol gap: the server never emitssession.createdunprompted on connect, and never emitssession.updatedin response to the client'ssession.update. Per the OpenAI Realtime protocol the server must sendsession.createdimmediately on connect, and conformant clients (and the real SDKs) wait for it before sendingsession.update. So they deadlock; the client waits on the server, the client-to-Bedrock forwarding loop waits on the client, and Bedrock waits on litellm. PR #31924's own QA client sidestepped this by sendingsession.updatewithout waiting forsession.created, so it was never caught. The only code that producedsession.createdwas gated on a Bedrock output event containingsessionStart, which Nova Sonic v1 never emits (it is an input-only event)The handler now emits a synthesized
session.createdto the client immediately after the bidirectional stream is established, independent of client input, and emitssession.updatedwhen the client sendssession.update. The event bodies are built by two smallBedrockRealtimeConfighelpers (session_created_event,session_updated_event) that share one_session_object; the existing reactivesessionStartmapping now delegates to the same builder, so its tested behavior is unchangedThe realtime handler lazily imports
aws-sdk-bedrock-runtime(plussmithy-aws-core), the experimental AWS SDK providingInvokeModelWithBidirectionalStream, which boto3 cannot do. That package was not declared anywhere inpyproject.toml, so a stock install raisedImportErrorand closed the socket with 1011 before the model could run. This adds it as a pinnedbedrock-realtimeoptional extra. Wiring the extra into the gateway image is tracked separatelyReview follow-ups: the
session.updatedack now reflects the client's requestedmodalitiesrather than a fixed["text", "audio"], so a text-onlysession.updateis acknowledged as text-only. The reactive BedrocksessionStartmapping no longer forwards a secondsession.created, sosession.createdis emitted exactly once (on connect) even if a compatible stream later emitssessionStartuv.lockis regenerated for the new extra.aws-sdk-bedrock-runtimerequires Python >=3.12 while litellm supports >=3.10, so the dependency carries apython_version >= '3.12'marker (same pattern as other version-gated extras); on 3.10/3.11 the extra is empty and the lazy import behaves as beforeFinal Attestation