@@ -49,7 +49,7 @@ def create_mock_async_websocket(messages=None):
4949
5050 # Create an iterator
5151 message_iter = iter (json_messages )
52-
52+
5353 async def mock_recv ():
5454 try :
5555 return next (message_iter )
@@ -83,7 +83,7 @@ async def test_async_conversation_basic_flow():
8383 # Run the test
8484 with patch ("elevenlabs.conversational_ai.conversation.websockets.connect" ) as mock_connect :
8585 mock_connect .return_value .__aenter__ .return_value = mock_ws
86-
86+
8787 await conversation .start_session ()
8888
8989 # Wait a bit for the callback to be called
@@ -97,7 +97,7 @@ async def test_async_conversation_basic_flow():
9797 init_messages = [json .loads (call ) for call in send_calls if 'conversation_initiation_client_data' in call ]
9898 assert len (init_messages ) == 1
9999 init_message = init_messages [0 ]
100-
100+
101101 assert init_message ["type" ] == "conversation_initiation_client_data"
102102 assert init_message ["custom_llm_extra_body" ] == {}
103103 assert init_message ["conversation_config_override" ] == {}
@@ -134,7 +134,7 @@ async def test_async_conversation_with_auth():
134134 # Run the test
135135 with patch ("elevenlabs.conversational_ai.conversation.websockets.connect" ) as mock_connect :
136136 mock_connect .return_value .__aenter__ .return_value = mock_ws
137-
137+
138138 await conversation .start_session ()
139139 await conversation .end_session ()
140140 await conversation .wait_for_session_end ()
@@ -166,7 +166,7 @@ async def test_async_conversation_with_dynamic_variables():
166166 # Run the test
167167 with patch ("elevenlabs.conversational_ai.conversation.websockets.connect" ) as mock_connect :
168168 mock_connect .return_value .__aenter__ .return_value = mock_ws
169-
169+
170170 await conversation .start_session ()
171171
172172 # Wait a bit for the callback to be called
@@ -180,7 +180,7 @@ async def test_async_conversation_with_dynamic_variables():
180180 init_messages = [json .loads (call ) for call in send_calls if 'conversation_initiation_client_data' in call ]
181181 assert len (init_messages ) == 1
182182 init_message = init_messages [0 ]
183-
183+
184184 assert init_message ["type" ] == "conversation_initiation_client_data"
185185 assert init_message ["custom_llm_extra_body" ] == {}
186186 assert init_message ["conversation_config_override" ] == {}
@@ -320,10 +320,10 @@ async def test_async_conversation_callback_flows():
320320 "audio_event" : {"event_id" : "789" , "audio_base_64" : "dGVzdA==" } # "test" in base64
321321 }
322322 ]
323-
323+
324324 mock_ws = create_mock_async_websocket (messages )
325325 mock_client = MagicMock ()
326-
326+
327327 # Setup callbacks
328328 agent_response_callback = AsyncMock ()
329329 agent_response_correction_callback = AsyncMock ()
@@ -349,7 +349,7 @@ async def test_async_conversation_callback_flows():
349349 mock_connect .return_value .__aenter__ .return_value = mock_ws
350350
351351 await conversation .start_session ()
352-
352+
353353 # Wait for callbacks to be processed
354354 await asyncio .sleep (0.2 )
355355
@@ -364,3 +364,53 @@ async def test_async_conversation_callback_flows():
364364 end_session_callback .assert_called_once ()
365365 assert conversation ._conversation_id == TEST_CONVERSATION_ID
366366 assert conversation ._last_interrupt_id == 456
367+
368+
369+ @pytest .mark .asyncio
370+ async def test_async_conversation_wss_url_generation_without_get_environment ():
371+
372+ from elevenlabs .core .client_wrapper import SyncClientWrapper
373+
374+ # Test with various base URL formats to ensure robustness
375+ test_cases = [
376+ ("https://api.elevenlabs.io" , "wss://api.elevenlabs.io" ),
377+ ("https://api.us.elevenlabs.io" , "wss://api.us.elevenlabs.io" ),
378+ ("https://api.eu.residency.elevenlabs.io" , "wss://api.eu.residency.elevenlabs.io" ),
379+ ("http://localhost:8000" , "ws://localhost:8000" ),
380+ ]
381+
382+ for base_url , expected_ws_base in test_cases :
383+ # Create a real SyncClientWrapper to ensure it doesn't have get_environment method
384+ mock_client = MagicMock ()
385+ mock_client ._client_wrapper = SyncClientWrapper (
386+ base_url = base_url ,
387+ api_key = "test_key" ,
388+ httpx_client = MagicMock (),
389+ timeout = 30.0
390+ )
391+
392+ conversation = AsyncConversation (
393+ client = mock_client ,
394+ agent_id = TEST_AGENT_ID ,
395+ requires_auth = False ,
396+ audio_interface = MockAsyncAudioInterface ()
397+ )
398+
399+ try :
400+ wss_url = conversation ._get_wss_url ()
401+
402+ # Verify the URL is correctly generated
403+ expected_url = f"{ expected_ws_base } /v1/convai/conversation?agent_id={ TEST_AGENT_ID } &source=python_sdk&version="
404+ assert wss_url .startswith (expected_url ), f"URL should start with { expected_url } , got { wss_url } "
405+
406+ # Verify the URL contains version parameter
407+ assert "version=" in wss_url , f"URL should contain version parameter, got { wss_url } "
408+
409+ except AttributeError as e :
410+ if "get_environment" in str (e ):
411+ assert False
412+ else :
413+ raise # Re-raise if it's a different AttributeError
414+
415+ except Exception as e :
416+ assert False , f"Unexpected error generating WebSocket URL: { e } "
0 commit comments