Lab L1.4: First Live Call
🎯 Assignment: Accept this lab on GitHub Classroom
You’ll get your own repository with starter code, instructions, and automatic grading.
| Duration | 60 minutes |
| Prerequisites | Previous module completed |
Objectives
- Connect agent to SignalWire
- Configure ngrok tunnel
- Make live test calls
- Debug real-time interactions
How to Complete This Lab
- Accept the Assignment — Click the GitHub Classroom link above
- Clone Your Repo —
git clone <your-repo-url> - Read the README — Your repo has detailed requirements and grading criteria
- Write Your Code — Implement the solution in
solution/agent.py - Test Locally — Use
swaig-testto verify your agent works - Push to Submit —
git pushtriggers auto-grading
Key Concepts
The following exercises walk through the concepts you’ll need. Your GitHub Classroom repo README has the specific requirements for grading.
Exercise 1: Prepare Your Agent
Create a production-ready agent:
Create live_agent.py:
#!/usr/bin/env python3
"""Agent ready for live calls."""
import os
from signalwire_agents import AgentBase
agent = AgentBase(
name="live-agent",
route="/agent"
)
# Basic authentication
auth_user = os.getenv("AUTH_USER", "signalwire")
auth_pass = os.getenv("AUTH_PASS", "training123")
agent.set_params({
"swml_basic_auth_user": auth_user,
"swml_basic_auth_password": auth_pass,
})
# Prompt
agent.prompt_add_section(
"Role",
"You are a friendly training assistant for SignalWire. "
"Greet callers warmly and have a brief conversation. "
"Ask them what they're learning about today."
)
agent.prompt_add_section(
"Guidelines",
bullets=[
"Keep responses brief - this is a phone call",
"Be enthusiastic about voice AI",
"If asked about SignalWire, say you're a demo agent"
]
)
# Voice configuration with fillers
# Using both speech_fillers AND function_fillers outputs them as separate fields
agent.add_language(
name="English",
code="en-US",
voice="rime.spore",
speech_fillers=["Um", "Uh", "Well", "Let me think"],
function_fillers=["One moment please", "Let me check that for you"]
)
if __name__ == "__main__":
agent.run()
Note on Fillers: When you provide BOTH
speech_fillersANDfunction_fillers, they appear as separate fields in the SWML output. If you only provide one type, it uses the deprecatedfillersfield.
Test locally:
swaig-test live_agent.py --dump-swml
Exercise 2: Start Agent Server
Run your agent:
python live_agent.py
Keep this terminal running!
Verify it’s working:
# In another terminal
curl http://localhost:3000/agent
You should see SWML JSON.
Exercise 3: Start ngrok Tunnel
In a new terminal:
# Option A: Random URL
ngrok http 3000
# Option B: Static domain (if you have one)
ngrok http 3000 --domain=your-name.ngrok-free.app
Record your forwarding URL:
Forwarding URL: https://_________________.ngrok.io
Exercise 4: Test Tunnel
Verify the tunnel works:
# Without auth (should fail)
curl https://YOUR-URL.ngrok.io/agent
# Expected: 401 Unauthorized
# With auth (should work)
curl https://signalwire:training123@YOUR-URL.ngrok.io/agent
# Expected: SWML JSON
Checkpoint: Both tests behave as expected.
Exercise 5: Configure SignalWire
- Log in to SignalWire dashboard
- Navigate to Phone Numbers
- Click on your phone number
- Find Voice and Fax Settings
- Configure:
| Setting | Value |
|---|---|
| Handle calls using | SWML Script |
| URL | https://signalwire:training123@YOUR-URL.ngrok.io/agent |
| HTTP Method | POST |
- Click Save
Important: Replace YOUR-URL with your actual ngrok URL!
Exercise 6: Make Your First Call
Preparation Checklist:
- Agent running in terminal 1
- ngrok running in terminal 2
- SignalWire configured with your URL
Make the Call:
- Call your SignalWire phone number
- Wait for your agent to answer
- Have a brief conversation
- Hang up when done
What to Try:
- Say “Hello”
- Ask “What can you do?”
- Ask “What am I learning today?”
Exercise 7: Monitor the Call
While calling, watch:
Terminal 1 (Agent):
INFO: POST /agent HTTP/1.1 200 OK
INFO: POST /agent/swaig HTTP/1.1 200 OK
Terminal 2 (ngrok): Shows requests coming through the tunnel.
ngrok Inspector: Open http://127.0.0.1:4040 to see:
- Request details
- Response bodies
- Timing information
Exercise 8: Troubleshooting Practice
If your call didn’t work, diagnose:
Step 1: Agent running?
curl http://localhost:3000/agent
Should return SWML.
Step 2: ngrok tunnel working?
curl https://YOUR-URL.ngrok.io/agent
Should return 401 (auth required).
Step 3: Auth correct?
curl https://signalwire:training123@YOUR-URL.ngrok.io/agent
Should return SWML.
Step 4: SignalWire URL correct? Double-check the URL in SignalWire dashboard.
Common Issues:
| Problem | Cause | Fix |
|---|---|---|
| No answer | Agent not running | Start agent |
| Fast busy | ngrok down | Restart ngrok |
| “Cannot connect” | Wrong URL | Fix SignalWire URL |
| Silence | Auth failed | Check credentials |
Exercise 9: Make Changes Live
Without stopping anything:
- Edit
live_agent.py - Change the prompt
- Save the file
Hot reload:
- The agent auto-reloads on file change
- Call again to hear the new behavior
Try changing:
- Greeting style
- Voice (try
rime.marsh) - Filler phrases
Exercise 10: Clean Shutdown
Proper shutdown sequence:
- Press
Ctrl+Cin agent terminal - Press
Ctrl+Cin ngrok terminal - Update SignalWire to remove URL (or leave for later)
Deliverables
Record and submit:
- Screenshot of ngrok running
- Screenshot of SignalWire configuration
- Brief notes on your conversation with the agent
Review Questions
- Why do we need ngrok for development?
- What does the authentication protect against?
- What URL format includes credentials?
- How do you debug when calls don’t work?
- What happens when you change the agent while running?
Summary
You have successfully:
- Prepared an agent for live calls
- Set up ngrok tunnel
- Configured authentication
- Connected SignalWire phone number
- Made your first live AI call!
Congratulations! You’ve completed the core Day 1 objectives.
Next: Day 2 - Prompt Engineering and Functions
Complete Agent Code
Click to reveal complete solution
#!/usr/bin/env python3
"""Agent ready for live calls with authentication.
Lab 1.4 Deliverable: Production-ready agent configured for live calls
with basic authentication, prompts, and voice settings.
Environment variables:
SWML_BASIC_AUTH_USER: Basic auth username (auto-detected by SDK)
SWML_BASIC_AUTH_PASSWORD: Basic auth password (auto-detected by SDK)
"""
from signalwire_agents import AgentBase
agent = AgentBase(
name="live-agent",
route="/agent"
)
# Prompt configuration
agent.prompt_add_section(
"Role",
"You are a friendly training assistant for SignalWire. "
"Greet callers warmly and have a brief conversation. "
"Ask them what they're learning about today."
)
agent.prompt_add_section(
"Guidelines",
bullets=[
"Keep responses brief - this is a phone call",
"Be enthusiastic about voice AI",
"If asked about SignalWire, say you're a demo agent"
]
)
# Voice configuration with fillers
# Using both speech_fillers AND function_fillers outputs them as separate fields
agent.add_language(
name="English",
code="en-US",
voice="rime.spore",
speech_fillers=["Um", "Uh", "Well", "Let me think"],
function_fillers=["One moment please", "Let me check that for you"]
)
if __name__ == "__main__":
agent.run()