wooden-lunch-47326
07/23/2025, 4:41 PMinterrupt_before= on the graph.compile step or is that handled automatically? My Agent is not saying anything when I dial in.tall-airline-16756
07/23/2025, 4:41 PMtall-airline-16756
07/23/2025, 4:44 PMwooden-lunch-47326
07/23/2025, 6:48 PMimport logging
from typing import Optional
from uuid import UUID, uuid4, uuid5
from langchain_core.messages import AIMessage, HumanMessage
from langchain_openai.chat_models import ChatOpenAI
from langgraph.graph import StateGraph, add_messages
from langgraph.types import StreamWriter, interrupt
from livekit.agents import Agent, AgentSession, AutoSubscribe
from livekit.plugins import deepgram, langchain, openai, silero
from typing_extensions import Annotated, TypedDict
from revin_voice_agent.agents.graphs.util.types import TypedLivekit
from revin_voice_agent.utils.config import get_settings
logger = logging.getLogger(__name__)
class AgentState(TypedDict):
messages: Annotated[list, add_messages]
user_name: Optional[str]
async def ask_name(state: AgentState, writer: StreamWriter) -> AgentState:
"""Ask for the user's name"""
livekit = TypedLivekit(writer)
livekit.say("Hello! What's your name?")
# Wait for user response
name, name_msgs = interrupt("user_name")
<http://logger.info|logger.info>(f"User name received: {name}")
return {"user_name": name, "messages": name_msgs}
async def write_sonnet(state: AgentState, writer: StreamWriter) -> AgentState:
"""Write a sonnet using the user's name"""
livekit = TypedLivekit(writer)
# Generate a sonnet using the user's name
prompt = f"Write a beautiful sonnet that includes the name '{state['user_name']}'. Make it poetic and personal."
response = await ChatOpenAI(model="gpt-4o-mini").ainvoke([HumanMessage(content=prompt)])
# Say the sonnet
livekit.say(response.content)
livekit.flush()
<http://logger.info|logger.info>(f"Generated sonnet for {state['user_name']}")
return {"messages": [AIMessage(content=f"Sonnet for {state['user_name']}: {response.content}")]}
async def say_goodbye(state: AgentState, writer: StreamWriter) -> AgentState:
"""Say goodbye to the user"""
livekit = TypedLivekit(writer)
livekit.say(f"Thank you for listening, {state['user_name']}. Goodbye!")
livekit.flush()
<http://logger.info|logger.info>(f"Said goodbye to {state['user_name']}")
return {"messages": [AIMessage(content=f"Conversation ended with {state['user_name']}")]}
# Build the graph
builder = StateGraph(AgentState)
# Add nodes
builder.add_node("ask_name", ask_name)
builder.add_node("write_sonnet", write_sonnet)
builder.add_node("say_goodbye", say_goodbye)
# Set entry point
builder.set_entry_point("ask_name")
# Add edges to create the flow
builder.add_edge("ask_name", "write_sonnet")
builder.add_edge("write_sonnet", "say_goodbye")
# Compile the graph
graph = builder.compile()
def prewarm(proc):
"""Prewarm function for the minimal voice agent"""
proc.userdata["vad"] = silero.VAD.load()
async def entrypoint(ctx):
"""Entrypoint function for the minimal voice agent"""
<http://logger.info|logger.info>(f"connecting to room {ctx.room.name}")
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
participant = await ctx.wait_for_participant()
# Generate thread ID
NAMESPACE = UUID("41010b5d-5447-4df5-baf2-97d69f2e9d06")
if participant.sid is not None:
thread_id = str(uuid5(NAMESPACE, participant.sid))
else:
thread_id = str(uuid4())
<http://logger.info|logger.info>(
f"starting minimal voice assistant for participant {participant.identity} (thread ID: {thread_id})"
)
settings = get_settings()
agent = Agent(
instructions="", # Instructions are handled by the LangGraph
llm=langchain.LLMAdapter(
graph=graph,
config={"configurable": {"thread_id": thread_id}},
),
)
# Create voice pipeline agent with our compiled graph
session: AgentSession = AgentSession(
stt=deepgram.STT(model=settings.deepgram.stt_model),
tts=openai.TTS(
model=settings.openai.tts_model,
voice=settings.openai.tts_voice,
),
vad=silero.VAD.load(),
min_endpointing_delay=0.5,
max_endpointing_delay=5.0,
)
await session.start(room=ctx.room, agent=agent)