This example is a basic agent that can answer inbound phone calls. This doesn't require any SIP-specific code. When you point a LiveKit phone number at a dispatch rule, SIP callers are automatically delivered into the room and the running agent greets them.
Prerequisites
- Buy a phone number in the LiveKit dashboard and create a dispatch rule that targets your worker:
- Buy a number: Telephony → Phone Numbers → Buy number → Create dispatch rule
- Add a
.env.localin this directory with your LiveKit credentials:LIVEKIT_URL=your_livekit_urlLIVEKIT_API_KEY=your_api_keyLIVEKIT_API_SECRET=your_api_secret - Install dependencies:pip install "livekit-agents" python-dotenv
Load environment, logging, and define an AgentServer
Start by importing the necessary modules and setting up the basic agent server. Load environment variables and configure logging for debugging.
import loggingfrom dotenv import load_dotenvfrom livekit.agents import JobContext, Agent, AgentSession, AgentServer, cli, inferenceload_dotenv(".env.local")logger = logging.getLogger("answer-call")logger.setLevel(logging.INFO)server = AgentServer()
Define the agent and session
Keep your Agent lightweight by only including the instructions.
Define STT, LLM, and TTS as part of your AgentSession inside the RTC session. Start your session with your agent and connect to the room.
import loggingfrom dotenv import load_dotenvfrom livekit.agents import JobContext, Agent, AgentSession, AgentServer, cli, inferenceload_dotenv(".env.local")logger = logging.getLogger("answer-call")logger.setLevel(logging.INFO)server = AgentServer()class SimpleAgent(Agent):def __init__(self) -> None:super().__init__(instructions="""You are a helpful agent.""")async def on_enter(self):self.session.generate_reply()@server.rtc_session(agent_name="my-agent")async def my_agent(ctx: JobContext):ctx.log_context_fields = {"room": ctx.room.name}session = AgentSession(stt=inference.STT(model="deepgram/nova-3-general"),llm=inference.LLM(model="google/gemma-4-31b-it"),tts=inference.TTS(model="inworld/inworld-tts-2", voice="Ashley"),preemptive_generation=True,)agent = SimpleAgent()await session.start(agent=agent, room=ctx.room)await ctx.connect()
Run the server
The cli.run_app() function starts the agent server. It manages the worker lifecycle, connects to LiveKit, and processes incoming jobs. When you run the script, it listens for incoming calls and automatically spawns agent sessions when calls arrive.
import loggingfrom dotenv import load_dotenvfrom livekit.agents import JobContext, Agent, AgentSession, AgentServer, cli, inferenceload_dotenv(".env.local")logger = logging.getLogger("answer-call")logger.setLevel(logging.INFO)server = AgentServer()class SimpleAgent(Agent):def __init__(self) -> None:super().__init__(instructions="""You are a helpful agent.""")async def on_enter(self):self.session.generate_reply()@server.rtc_session(agent_name="my-agent")async def my_agent(ctx: JobContext):ctx.log_context_fields = {"room": ctx.room.name}session = AgentSession(stt=inference.STT(model="deepgram/nova-3-general"),llm=inference.LLM(model="google/gemma-4-31b-it"),tts=inference.TTS(model="inworld/inworld-tts-2", voice="Ashley"),preemptive_generation=True,)agent = SimpleAgent()await session.start(agent=agent, room=ctx.room)await ctx.connect()if __name__ == "__main__":cli.run_app(server)
Run it
Run the agent using the console command, which starts the agent in console mode. This mode is useful for testing and debugging. It connects to a mocked LiveKit room so you can test the agent locally before deploying. This will not work for real phone calls (since the room is mocked), but it's a great way to quickly test that your agent works.
lk agent console answer_call.py
If you want to test your agent with a real phone call, you'll need to start it in dev mode instead. This will connect your agent to a LiveKit server, which makes it available to your dispatch rules.
lk agent dev answer_call.py
How inbound calls connect
- An inbound call hits your LiveKit number.
- The dispatch rule attaches the SIP participant to your room.
- If the worker is running, the agent is already in the room and responds immediately — no special SIP handling needed.
Complete code for the call answering agent
import loggingfrom dotenv import load_dotenvfrom livekit.agents import JobContext, Agent, AgentSession, AgentServer, cli, inferenceload_dotenv(".env.local")logger = logging.getLogger("answer-call")logger.setLevel(logging.INFO)server = AgentServer()class SimpleAgent(Agent):def __init__(self) -> None:super().__init__(instructions="""You are a helpful agent.""")async def on_enter(self):self.session.generate_reply()@server.rtc_session(agent_name="my-agent")async def my_agent(ctx: JobContext):ctx.log_context_fields = {"room": ctx.room.name}session = AgentSession(stt=inference.STT(model="deepgram/nova-3-general"),llm=inference.LLM(model="google/gemma-4-31b-it"),tts=inference.TTS(model="inworld/inworld-tts-2", voice="Ashley"),preemptive_generation=True,)agent = SimpleAgent()await session.start(agent=agent, room=ctx.room)await ctx.connect()if __name__ == "__main__":cli.run_app(server)