I'm trying to build a "Phone Collector Agent", res...
# ask-ai
t
I'm trying to build a "Phone Collector Agent", responsible solely for collecting the caller's phone number using DTMF inputs. Here's what I've done so far. I'm wondering if there's a better way to handle that, as I encountered the following problems: 1. If I speak while input my phone number (and pressing #), the bot might speak and not tell the "thank you" done after the check 2. The might might even not call the tool for validation. This tool call is mandatory to be able to transfer to the "Welcome Agent" once phone number is valid 3. Once transfering to the Welcome Agent, despite the fact that I asked the bot not to greet the caller a second time, it might greet them anyway
t
Thanks for reaching out, Pierrick. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
To help you out with your Phone Collector Agent setup, could you share a bit more about a few things? • Are you using any specific LiveKit tools or APIs for handling and validating DTMF input? • How have you integrated the validation tool into your current setup? • Can you tell me more about how the transfer to the "Welcome Agent" is set up, especially how the greeting works? Knowing these details will really help us get to the bottom of the issues you're facing and find the best solution for you. Sources: README.md | Company directory phone assistant | LiveKit Docs | Handling DTMF | LiveKit Docs
t
Everything about the phone collector is in the code snipper I attached to the first message. The greeting is just a prompt telling the bot to greet the patient
t
Hey there! It looks like the code snippet you mentioned didn’t come through. Could you please share it again? That way, I can get a better idea of what you’re working with and help you out more effectively.
t
import asyncio from typing import Tuple, Union from livekit.agents import Agent, function_tool from livekit.rtc import SipDTMF from loguru import logger from models.clinics import ClinicConfig from models.user_data import RunContext_T from services.patients import retrieve_existing_patient, RetrievePatientRequest from utils.phone_number import is_valid_french_mobile_phone_number from utils.prompts import GENERAL_INSTRUCTIONS, build_greeting_prompt def build_system_prompt(clinic_config: ClinicConfig) -> str: return f""" {GENERAL_INSTRUCTIONS} Your job is to greet the patient and collect their mobile phone number before going further: 1. {build_greeting_prompt(clinic_config.name)} 2. Ask them politely that you need them to input their mobile phone number and terminate with a # before going further Example in French: "Afin de poursuivre, merci de composer votre numéro de portable suivi de la touche dièse." """ class PhoneCollectorAgent(Agent): def __init__(self, clinic_config: ClinicConfig) -> None: super().__init__(instructions=build_system_prompt(clinic_config)) self.phone_number = "" async def on_enter(self) -> None: self.session.userdata.ctx.room.on( "sip_dtmf_received", self.on_sip_dtmf_received ) await self.session.generate_reply() def on_sip_dtmf_received(self, dtmf_event: SipDTMF) -> None: asyncio.create_task(self._handle_dtmf(dtmf_event)) async def _handle_dtmf(self, dtmf_event: SipDTMF) -> None: # Update user state so the idle callback doesn't get triggered self.session._update_user_state("speaking") digit = dtmf_event.digit logger.info(f"Received DTMF: {digit}") if digit not in ["#", "*"]: self.phone_number += digit else: # Termination digit logger.info(f"Final phone number: {self.phone_number}") await self.session.generate_reply( instructions="Call the
validate_phone_number
tool" ) @function_tool() async def validate_phone_number( self, context: RunContext_T ) -> Union[str, Tuple[Agent, str]]: """ Called when the user has entered their phone number and terminated with a # """ logger.info(f"Validating phone number: {self.phone_number}") if not is_valid_french_mobile_phone_number(self.phone_number): self.phone_number = "" return "The number is incorrect. Ask the patient to try again" context.userdata.ctx.room.off("sip_dtmf_received", self._handle_dtmf) await self.session.generate_reply( instructions="Thank the patient and tell them their phone number has been registered" ) retrieved_patient = await retrieve_existing_patient( context.userdata.config_id, RetrievePatientRequest(phone_number=self.phone_number), ) if retrieved_patient: context.userdata.retrieved_patient = retrieved_patient welcome_agent = context.userdata.agents["welcome"] # TODO FIXME: context.userdata.agents should be a dict of BaseAgent (but it creates a circular import) welcome_agent.mute_on_enter = True # type: ignore return welcome_agent, "Don't greet the patient, just ask them how you can help"
t
Here are some handy tips to help you sort out the issues in your Phone Collector Agent setup: • Overlapping Speech: Try setting
allow_interruptions=False
during key moments like validation or when thanking the user. This way, the bot’s speech won’t get cut off by DTMF inputs or other events. • Mandatory Validation Tool Calls: Make sure the validation tool always runs by configuring the tool execution flow. Setting
tool_choice='required'
can help keep this consistent. • Duplicate Greetings: To avoid repeating greetings, add some state tracking in your agent’s
on_enter
method. For example, use a flag like
self._greeting_delivered
to check if the greeting’s already been sent. If you want, I’d be happy to walk you through the details of implementing any of these fixes! Sources: README.md | Agent speech and audio | LiveKit Docs | agents/src/pipeline/pipeline_agent.ts