Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions MANCHESTER_DEMO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Manchester, NH Telephone Agent Demo

This voice AI agent is specifically configured for demonstrating to local subscribers around Manchester, New Hampshire. It provides a professional telephone experience with local knowledge and information.

## Features

### Manchester-Specific Knowledge
The agent is pre-configured with information about:
- Local geography and landmarks (Merrimack River, Amoskeag Millyard)
- Major attractions (Currier Museum of Art, SNHU Arena, Palace Theatre)
- Manchester-Boston Regional Airport
- Historic context and local culture

### Local Information Tool
The agent includes a `get_local_info` tool that provides detailed information about:
- **Restaurants & Dining**: Local favorites like Red Arrow Diner, Copper Door, Hanover Street Chop House
- **Parks & Recreation**: Livingston Park, Derryfield Park, Lake Massabesic, Amoskeag Fishways
- **Education**: Public schools, SNHU, Saint Anselm College, Manchester Community College
- **Healthcare**: Catholic Medical Center, Elliot Hospital, urgent care facilities
- **Shopping**: Mall of New Hampshire, downtown Elm Street shops, South Willow Street
- **Entertainment**: SNHU Arena, Palace Theatre, local events
- **History & Culture**: Amoskeag Mills history, Millyard Museum, historic architecture

### Telephone-Optimized Experience
The agent is designed for phone calls with:
- Professional, warm greeting suitable for telephone interaction
- Clear, concise responses optimized for voice-only communication
- No emojis, asterisks, or text formatting
- SIP/telephony noise cancellation enabled

## Setup

### Prerequisites
1. LiveKit Cloud account with API credentials
2. Environment variables configured in `.env.local`:
```
LIVEKIT_URL=your_livekit_url
LIVEKIT_API_KEY=your_api_key
LIVEKIT_API_SECRET=your_api_secret
```

### Installation
```bash
# Install dependencies
uv sync

# Download required models
uv run python src/agent.py download-files
```

## Running the Agent

### For Console Testing
```bash
uv run python src/agent.py console
```

### For Development (with Frontend or Telephony)
```bash
uv run python src/agent.py dev
```

### For Production
```bash
uv run python src/agent.py start
```

## Telephony Integration

To connect this agent to a phone number for your Manchester, NH demo:

1. Follow the [LiveKit Telephony Documentation](https://docs.livekit.io/agents/start/telephony/)
2. Configure a SIP trunk using the LiveKit CLI:
```bash
lk sip trunk create
```
3. Set up inbound or outbound calling as needed for your demo

The agent automatically applies telephony-optimized noise cancellation when connected via SIP.

## Testing

Run the test suite to validate Manchester-specific functionality:
```bash
uv run pytest
```

Tests include:
- Manchester location awareness
- Local information tool functionality
- Professional telephone greeting
- Standard agent behavior (grounding, safety)

## Example Interactions

**Greeting:**
- Caller: "Hello, can you help me?"
- Agent: *Provides warm, professional greeting and offers assistance*

**Local Information:**
- Caller: "What restaurants do you recommend?"
- Agent: *Uses get_local_info tool to provide Manchester dining options*

**Area Questions:**
- Caller: "Tell me about your city"
- Agent: *Shares information about Manchester, NH's history, location, and attractions*

## Customization

To adjust the agent for your specific demo needs:

1. **Update Instructions**: Edit the `instructions` parameter in `src/agent.py`
2. **Add Local Info**: Extend the `get_local_info` tool with more categories
3. **Adjust Voice/Model**: Modify the TTS voice or LLM model in the session setup

## Demo Tips

For the best demo experience:
- Use a quality microphone and quiet environment
- Speak clearly and naturally
- Try asking about different Manchester topics (restaurants, parks, schools)
- Demonstrate the agent's professional telephone demeanor
- Show how it handles local knowledge vs. general questions

## Support

For issues or questions about LiveKit Agents, see:
- [LiveKit Documentation](https://docs.livekit.io/)
- [LiveKit Agents Python SDK](https://github.com/livekit/agents)
- [LiveKit Community](https://livekit.io/community)
82 changes: 62 additions & 20 deletions src/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
AgentSession,
JobContext,
JobProcess,
RunContext,
cli,
function_tool,
inference,
room_io,
)
Expand All @@ -23,28 +25,68 @@
class Assistant(Agent):
def __init__(self) -> None:
super().__init__(
instructions="""You are a helpful voice AI assistant. The user is interacting with you via voice, even if you perceive the conversation as text.
You eagerly assist users with their questions by providing information from your extensive knowledge.
Your responses are concise, to the point, and without any complex formatting or punctuation including emojis, asterisks, or other symbols.
You are curious, friendly, and have a sense of humor.""",
instructions="""You are a friendly and professional voice AI assistant serving the Manchester, New Hampshire area. You are speaking with local subscribers over the telephone.

Your role is to:
- Greet callers warmly and professionally
- Provide information about local services and businesses in the Manchester, NH area
- Answer questions about the area, including neighborhoods, attractions, and local amenities
- Be knowledgeable about Manchester's history, culture, and community

Communication style:
- Keep responses concise and clear for telephone conversation
- Speak naturally without complex formatting, emojis, asterisks, or other symbols
- Be friendly, helpful, and patient
- If you don't know something specific, be honest and offer to help with related questions

Key information about Manchester, NH:
- Largest city in New Hampshire
- Located in Hillsborough County along the Merrimack River
- Known for the historic Amoskeag Millyard
- Home to the Manchester-Boston Regional Airport
- Features attractions like the Currier Museum of Art and SNHU Arena
- Vibrant downtown with local restaurants, shops, and entertainment""",
)

# To add tools, use the @function_tool decorator.
# Here's an example that adds a simple weather tool.
# You also have to add `from livekit.agents import function_tool, RunContext` to the top of this file
# @function_tool
# async def lookup_weather(self, context: RunContext, location: str):
# """Use this tool to look up current weather information in the given location.
#
# If the location is not supported by the weather service, the tool will indicate this. You must tell the user the location's weather is unavailable.
#
# Args:
# location: The location to look up weather information for (e.g. city name)
# """
#
# logger.info(f"Looking up weather for {location}")
#
# return "sunny with a temperature of 70 degrees."
@function_tool
async def get_local_info(self, context: RunContext, topic: str):
"""Use this tool to get information about local Manchester, NH services, attractions, or businesses.

Args:
topic: The topic or type of information requested (e.g., restaurants, parks, schools, healthcare, shopping)
"""

logger.info(f"Looking up local information for: {topic}")

# Provide helpful local information based on the topic
topic_lower = topic.lower()

if any(word in topic_lower for word in ["restaurant", "food", "dining"]):
return """Manchester has a diverse dining scene. Popular areas include downtown Elm Street with restaurants like The Copper Door and Hanover Street Chop House. The Millyard district also features great options. For casual dining, Red Arrow Diner is a local favorite open 24/7."""

elif any(word in topic_lower for word in ["park", "outdoor", "recreation"]):
return """Manchester offers several parks including Livingston Park with its scenic trails, Derryfield Park for sports and picnicking, and Lake Massabesic for water activities. The Amoskeag Fishways has walking paths along the Merrimack River."""

elif any(word in topic_lower for word in ["school", "education"]):
return """Manchester has a public school system with several elementary, middle, and high schools. The city is also home to Southern New Hampshire University (SNHU), Saint Anselm College, and Manchester Community College."""

elif any(word in topic_lower for word in ["healthcare", "hospital", "medical"]):
return """Catholic Medical Center and Elliot Hospital are the two main hospitals serving Manchester. Both offer comprehensive medical services and emergency care. There are also numerous urgent care facilities and medical practices throughout the city."""

elif any(word in topic_lower for word in ["shopping", "mall", "store"]):
return """The Mall of New Hampshire is a major shopping destination. Downtown Manchester on Elm Street has unique local shops and boutiques. The area also has various plazas and retail centers including the South Willow Street commercial district."""

elif any(word in topic_lower for word in ["airport", "travel"]):
return """Manchester-Boston Regional Airport (MHT) is conveniently located just minutes from downtown. It serves several major airlines with direct flights to many U.S. destinations."""

elif any(word in topic_lower for word in ["entertainment", "event", "arena"]):
return """The SNHU Arena hosts concerts, sporting events, and shows. The historic Palace Theatre downtown presents plays, concerts, and performances. The Currier Museum of Art features impressive collections and exhibitions."""

elif any(word in topic_lower for word in ["history", "museum"]):
return """Manchester's history is rooted in textile manufacturing at the Amoskeag Mills, once the largest cotton textile plant in the world. The Millyard Museum chronicles this history. The city has beautifully preserved historic architecture throughout downtown."""

else:
return f"""I can help with information about Manchester, NH. For specific details about {topic}, I recommend checking with local resources or asking about particular categories like restaurants, parks, schools, healthcare, shopping, or entertainment."""


server = AgentServer()
Expand Down
113 changes: 113 additions & 0 deletions tests/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,116 @@ async def test_refuses_harmful_request() -> None:

# Ensures there are no function calls or other unexpected events
result.expect.no_more_events()


@pytest.mark.asyncio
async def test_manchester_location_awareness() -> None:
"""Evaluation of the agent's awareness of Manchester, NH location."""
async with (
_llm() as llm,
AgentSession(llm=llm) as session,
):
await session.start(Assistant())

# Run an agent turn asking about the location
result = await session.run(user_input="What city are you serving?")

# Evaluate the agent's response mentions Manchester, NH
await (
result.expect.next_event()
.is_message(role="assistant")
.judge(
llm,
intent="""
Indicates that the assistant serves Manchester, New Hampshire.

The response should include reference to:
- Manchester (city name)
- New Hampshire or NH (state)

The response may also include:
- Additional context about the area
- Offers to help with local information
""",
)
)

result.expect.no_more_events()


@pytest.mark.asyncio
async def test_local_information_tool() -> None:
"""Evaluation of the agent's ability to provide local Manchester information."""
async with (
_llm() as llm,
AgentSession(llm=llm) as session,
):
await session.start(Assistant())

# Run an agent turn asking about local restaurants
result = await session.run(
user_input="Can you tell me about restaurants in the area?"
)

# Expect a tool call to get_local_info
result.expect.next_event().is_function_call(name="get_local_info")

# Expect the assistant's response with restaurant information
await (
result.expect.next_event()
.is_message(role="assistant")
.judge(
llm,
intent="""
Provides information about restaurants in Manchester, NH.

The response should:
- Mention specific restaurants or dining areas in Manchester
- Be helpful and informative about local dining options

The response may include:
- Specific restaurant names
- Areas known for dining (e.g., downtown, Elm Street)
- Types of cuisine available
""",
)
)

result.expect.no_more_events()


@pytest.mark.asyncio
async def test_professional_telephone_greeting() -> None:
"""Evaluation of the agent's professional telephone demeanor."""
async with (
_llm() as llm,
AgentSession(llm=llm) as session,
):
await session.start(Assistant())

# Run an agent turn with a typical phone greeting
result = await session.run(user_input="Hello, can you help me?")

# Evaluate the agent's response for professional friendliness
await (
result.expect.next_event()
.is_message(role="assistant")
.judge(
llm,
intent="""
Responds in a friendly and professional manner appropriate for a telephone conversation.

The response should:
- Be warm and welcoming
- Offer assistance
- Sound professional yet personable
- Be suitable for a phone conversation (clear, concise)

The response should not:
- Use emojis, asterisks, or text formatting
- Be overly casual or unprofessional
""",
)
)

result.expect.no_more_events()