| Duration | 2 hours |
| Day | 1 of 2 |
Learning Objectives
By the end of this module, students will be able to:
- Explain the structure of SWML documents
- Identify key SWML verbs and their purposes
- Understand how SignalWire processes SWML
- Trace the request/response lifecycle
Topics
1. What is SWML? (20 min)
SignalWire Markup Language
SWML (SignalWire Markup Language) is a JSON-based document format that tells SignalWire how to handle calls.
Key Concept
Your Agent creates SWML → SignalWire executes SWML → Caller experiences the result
Why SWML?
| Benefit | Description |
|---|---|
| Declarative | Describe what, not how |
| Portable | Works across deployments |
| Cacheable | Can be pre-generated |
| Debuggable | JSON is easy to inspect |
SWML vs Code
Traditional approach:
# Pseudo-code - handling each event
on_call_start:
say("Hello")
on_speech_detected:
process(speech)
generate_response()
say(response)
SWML approach:
{
"ai": {
"prompt": { "text": "You are helpful..." }
}
}
SignalWire handles all the event processing!
2. SWML Document Structure (30 min)
Basic Structure
{
"version": "1.0.0",
"sections": {
"main": [
{ "verb": { "parameters": "..." } }
]
}
}
Required Elements
| Element | Purpose |
|---|---|
version | SWML spec version (always “1.0.0”) |
sections | Container for call flows |
main | Default entry point |
Sections
Sections are named flows. main always executes first:
{
"version": "1.0.0",
"sections": {
"main": [
{ "ai": { "..." } }
],
"transfer_flow": [
{ "connect": { "..." } }
]
}
}
Verbs
Verbs are actions within sections:
{
"sections": {
"main": [
{ "answer": {} },
{ "play": { "url": "greeting.mp3" } },
{ "ai": { "prompt": { "text": "..." } } }
]
}
}
3. The AI Verb (30 min)
Core of Voice AI
The ai verb creates an AI-powered conversation:
{
"ai": {
"prompt": {
"text": "You are a helpful assistant."
},
"languages": [
{
"name": "English",
"code": "en-US",
"voice": "rime.spore"
}
]
}
}
AI Verb Components
{
"ai": {
"prompt": { }, // System instructions
"languages": [ ], // Voice configuration
"params": { }, // AI behavior settings
"SWAIG": { }, // Function definitions
"hints": [ ], // Speech recognition hints
"post_prompt": { } // Call summary instructions
}
}
Prompt Structure
{
"prompt": {
"text": "Main prompt text",
"temperature": 0.7,
"top_p": 0.9
}
}
Language Configuration
{
"languages": [
{
"name": "English",
"code": "en-US",
"voice": "rime.spore",
"speech_fillers": ["One moment...", "Let me check..."]
}
]
}
SWAIG Functions
{
"SWAIG": {
"functions": [
{
"function": "get_weather",
"description": "Get current weather",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string" }
}
}
}
],
"defaults": {
"web_hook_url": "https://your-agent.com/swaig"
}
}
}
4. Common SWML Verbs (25 min)
Answer
Pick up the call:
{ "answer": { "max_duration": 3600 } }
Play
Play audio file:
{ "play": { "url": "https://example.com/greeting.mp3" } }
Say (TTS)
Text-to-speech:
{ "say": { "text": "Hello, welcome to our service." } }
Connect
Transfer to another destination:
{
"connect": {
"to": "+15551234567",
"from": "+15559876543"
}
}
Hangup
End the call:
{ "hangup": { "reason": "completed" } }
Verb Reference Table
| Verb | Purpose | Key Parameters |
|---|---|---|
answer | Answer incoming call | max_duration |
hangup | End call | reason |
play | Play audio | url, volume |
say | Text-to-speech | text, voice |
ai | AI conversation | prompt, languages, SWAIG |
connect | Transfer call | to, from |
record | Record audio | format, stereo |
5. Request/Response Flow (15 min)
Initial Request
When a call arrives, SignalWire sends:
POST /your-agent HTTP/1.1
Content-Type: application/json
{
"call": {
"call_id": "abc123",
"from": "+15551234567",
"to": "+15559876543",
"direction": "inbound"
}
}
Your Response
Your agent returns SWML:
HTTP/1.1 200 OK
Content-Type: application/json
{
"version": "1.0.0",
"sections": {
"main": [
{
"ai": {
"prompt": { "text": "..." }
}
}
]
}
}
Function Calls
During conversation, SignalWire calls your SWAIG endpoint:
POST /your-agent/swaig HTTP/1.1
Content-Type: application/json
{
"function": "get_weather",
"argument": {
"parsed": [{ "city": "Seattle" }]
}
}
Your response:
{
"response": "The weather in Seattle is 65°F and cloudy."
}
SDK Abstraction
What You Write
agent = AgentBase(name="my-agent")
agent.prompt_add_section("Role", "You are helpful.")
agent.add_language("English", "en-US", "rime.spore")
@agent.tool(
description="Get weather",
parameters={
"type": "object",
"properties": {
"city": {"type": "string", "description": "The city to get weather for"}
},
"required": ["city"]
}
)
def get_weather(args: dict, raw_data: dict = None) -> SwaigFunctionResult:
city = args.get("city", "")
return f"Weather in {city}: 65°F"
What Gets Generated
{
"version": "1.0.0",
"sections": {
"main": [
{
"ai": {
"prompt": {
"text": "# Role\nYou are helpful."
},
"languages": [{
"name": "English",
"code": "en-US",
"voice": "rime.spore"
}],
"SWAIG": {
"functions": [{
"function": "get_weather",
"description": "Get weather",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string" }
}
}
}]
}
}
}
]
}
}
The SDK handles all the JSON generation!
Key Takeaways
- SWML is declarative - Describe the experience, not the implementation
- JSON structure is fixed - version, sections, main
- AI verb is the core - Most voice AI uses this
- SDK generates SWML - You write Python, it creates JSON
- Inspect with swaig-test - Always verify generated output
Common Mistakes
1. Invalid JSON
SWML must be valid JSON. Use swaig-test --dump-swml to validate.
2. Missing Main Section
Every SWML needs a main section in sections.
3. Wrong Verb Order
Verbs execute sequentially. answer should come before ai.
Preparation for Lab 1.3
- Have a working agent from Lab 1.2
- swaig-test ready
- Text editor for JSON inspection
Lab Preview
In Lab 1.3, you will:
- Generate SWML from your agent
- Modify AI parameters
- Trace the call flow
- Understand function registration