", "pid": 49999, "job_id": "AJ_VQF4RDSrX3sj"} 5-08...
# ask-ai
r
", "pid": 49999, "job_id": "AJ_VQF4RDSrX3sj"} 2025-08-11 001349,404 - ERROR livekit.agents - Error in _bounce_eou_task Traceback (most recent call last): File "/Users/rhythmvij/Desktop/LupitorNewProjects/VoiceAgent/venv/lib/python3.13/site-packages/livekit/agents/utils/log.py", line 16, in async_fn_logs return await fn(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/rhythmvij/Desktop/LupitorNewProjects/VoiceAgent/venv/lib/python3.13/site-packages/livekit/agents/voice/audio_recognition.py", line 351, in _bounce_eou_task if not await turn_detector.supports_language(self._last_language): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: object bool can't be used in 'await' expression {"pid": 49999, "job_id": "AJ_VQF4RDSrX3sj"}
t
Thanks for reaching out, Rhythm. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Hey there! That error, "TypeError: object bool can't be used in 'await' expression," pops up when you try to use
await
on a boolean value — which unfortunately isn’t allowed. The
await
keyword works only with awaitable things like coroutines or futures. Here are a few common reasons this might happen and how you can fix them: • Awaiting a Boolean Variable: Double-check that the thing you’re awaiting is actually a coroutine or future, not just a True or False. For example, instead of
await True
, try using a condition like
if condition:
. • Returning a Boolean in an Async Function: Async functions should return awaitable objects, so try to avoid returning a boolean directly from them. • Awaiting Expressions That Evaluate to Booleans: If a function gives back a boolean, don’t put
await
in front of it. Just save the result and use it in an if-statement or wherever you need. To get this sorted, take a look at where the error shows up and make sure every
await
is used with something awaitable. If you want, feel free to share your code snippet, and I’d be happy to help you troubleshoot it more specifically!
r
code:_from_ future import annotations import asyncio import logging from dotenv import load_dotenv import json import os from typing import Any from livekit import rtc, api from livekit.agents import ( AgentSession, Agent, JobContext, function_tool, RunContext, get_job_context, cli, WorkerOptions, RoomInputOptions, ) from livekit.plugins import ( deepgram, openai, cartesia, silero, noise_cancellation, # noqa: F401 ) from livekit.plugins.turn_detector.english import EnglishModel from livekit.plugins.turn_detector.multilingual import MultilingualModel # load environment variables, this is optional, only used for local development load_dotenv(_dotenv_path_=".env") logger = logging.getLogger("outbound-caller") logger.setLevel(logging.INFO) outbound_trunk_id = os.getenv("SIP_OUTBOUND_TRUNK_ID") class OutboundCaller(Agent): def __init__( self, *, _name_: str, _appointment_time_: str, _dial_info_: dict[str, Any], ): super().__init__( instructions=f""" You are a scheduling assistant for a dental practice. Your interface with user will be voice. You will be on a call with a patient who has an upcoming appointment. Your goal is to confirm the appointment details. As a customer service representative, you will be polite and professional at all times. Allow user to end the conversation. When the user would like to be transferred to a human agent, first confirm with them. upon confirmation, use the transfer_call tool. The customer's name is {name}. His appointment is on {appointment_time}. """ ) # keep reference to the participant for transfers self.participant: rtc.RemoteParticipant | None = None self.dial_info = dial_info def set_participant(self, _participant_: rtc.RemoteParticipant): self.participant = participant async def hangup(self): """Helper function to hang up the call by deleting the room""" job_ctx = get_job_context() await job_ctx.api.room.delete_room( api.DeleteRoomRequest( room=job_ctx.room.name, ) ) @function_tool() async def transfer_call(self, _ctx_: RunContext): """Transfer the call to a human agent, called after confirming with the user""" transfer_to = self.dial_info["transfer_to"] if not transfer_to: return "cannot transfer call" logger.info(f"transferring call to {transfer_to}") # let the message play fully before transferring await ctx.session.generate_reply( instructions="let the user know you'll be transferring them" ) job_ctx = get_job_context() _try_: await job_ctx.api.sip.transfer_sip_participant( api.TransferSIPParticipantRequest( _room_name_=job_ctx.room.name, _participant_identity_=self.participant.identity, _transfer_to_=f"tel:{transfer_to}", ) ) logger.info(f"transferred call to {transfer_to}") except Exception as e: logger.error(f"error transferring call: {e}") await ctx.session.generate_reply( instructions="there was an error transferring the call." ) await self.hangup() @function_tool() async def end_call(self, _ctx_: RunContext): """Called when the user wants to end the call""" logger.info(f"ending the call for {self.participant.identity}") # let the agent finish speaking current_speech = ctx.session.current_speech if current_speech: await current_speech.wait_for_playout() await self.hangup() @function_tool() async def look_up_availability( self, _ctx_: RunContext, _date_: str, ): """Called when the user asks about alternative appointment availability Args: date: The date of the appointment to check availability for """ logger.info( f"looking up availability for {self.participant.identity} on {date}" ) await asyncio.sleep(3) return { "available_times": ["1pm", "2pm", "3pm"], } @function_tool() async def confirm_appointment( self, _ctx_: RunContext, _date_: str, _time_: str, ): """Called when the user confirms their appointment on a specific date. Use this tool only when they are certain about the date and time. Args: date: The date of the appointment time: The time of the appointment """ logger.info( f"confirming appointment for {self.participant.identity} on {date} at {time}" ) return "reservation confirmed" @function_tool() async def detected_answering_machine(self, _ctx_: RunContext): """Called when the call reaches voicemail. Use this tool AFTER you hear the voicemail greeting""" logger.info(f"detected answering machine for {self.participant.identity}") await self.hangup() async def entrypoint(_ctx_: JobContext): logger.info(f"connecting to room {ctx.room.name}") await ctx.connect() # when dispatching the agent, we'll pass it the approriate info to dial the user _# dial_info is a dict with the following keys:_ _# - phone_number: the phone number to dial_ _# - transfer_to: the phone number to transfer the call to when requested_ dial_info = json.loads(ctx.job.metadata) participant_identity = phone_number = dial_info["phone_number"] # look up the user's phone number and appointment details agent = OutboundCaller( name="Jayden", _appointment_time_="next Tuesday at 3pm", _dial_info_=dial_info, ) # the following uses GPT-4o, Deepgram and Cartesia session = AgentSession( _turn_detection_=MultilingualModel(), vad=silero.VAD.load(), stt=deepgram.STT(), # you can also use OpenAI's TTS with openai.TTS() tts=cartesia.TTS(), llm=openai.LLM(model="gpt-4o"), # you can also use a speech-to-speech model like OpenAI's Realtime API # llm=openai.realtime.RealtimeModel() ) # start the session first before dialing, to ensure that when the user picks up # the agent does not miss anything the user says session_started = asyncio.create_task( session.start( agent=agent, room=ctx.room, _room_input_options_=RoomInputOptions( # enable Krisp background voice and noise removal _noise_cancellation_=noise_cancellation.BVCTelephony(), ), ) ) _#
create_sip_participant
starts dialing the user_ _try_: await ctx.api.sip.create_sip_participant( api.CreateSIPParticipantRequest( _room_name_=ctx.room.name, _sip_trunk_id_=outbound_trunk_id, _sip_call_to_=phone_number, _participant_identity_=participant_identity, # function blocks until user answers the call, or if the call fails _wait_until_answered_=True, ) ) # wait for the agent session start and participant join await session_started participant = await ctx.wait_for_participant(identity=participant_identity) logger.info(f"participant joined: {participant.identity}") agent.set_participant(participant) except api.TwirpError as e: logger.error( f"error creating SIP participant: {e.message}, " f"SIP status: {e.metadata.get('sip_status_code')} " f"{e.metadata.get('sip_status')}" ) ctx.shutdown() if name == "__main__": cli.run_app( WorkerOptions( _entrypoint_fnc_=entrypoint, _agent_name_="outbound-caller", ) )
t
Hey there! If you’re running into async/await issues with your LiveKit setup, especially when working with turn detection models like
MultilingualModel
or
EnglishModel
, here are some friendly tips to help you troubleshoot: • Make Sure Async/Await is Used Properly: Double-check that all your async functions—like those in your turn detection models—are awaited correctly. Missing this can cause unexpected errors. • STT and Model Setup: Confirm that your STT plugin is set up right and matches the language your turn detection model expects. • Initialization: Make sure your
AgentSession
includes everything it needs—STT, VAD, and the turn detection models—before you start. • Logging: Turn on detailed logging to keep an eye on what your models are outputting. Adding some custom logs can also give you extra clarity. • Error Handling: Wrap your async calls in try/catch blocks to catch and log any errors smoothly. • Performance: Consider using compute-optimized instances to keep things running quickly during inference. If you want, feel free to share the exact part of your code that’s giving you trouble—I’d be happy to help you dive deeper and find a solution together!