Lifecycle

View as Markdown

Request Lifecycle

Trace the complete journey of a call through the SignalWire Agents SDK, from incoming call to conversation end.

The Complete Call Flow

Understanding the request lifecycle helps you debug issues and optimize your agents. Here’s the complete flow:

Complete Call Lifecycle.
Complete Call Lifecycle

Phase 1: Call Setup

When a call arrives at SignalWire:

Call Setup.
Call Setup

Key points:

  • SignalWire knows which agent to contact based on phone number configuration
  • The request includes Basic Auth credentials
  • POST is the default; GET requests are also supported for SWML retrieval

Phase 2: SWML Generation

Your agent builds and returns the SWML document:

1## Inside AgentBase._render_swml()
2
3def _render_swml(self, request_body=None):
4 """Generate SWML document for this agent."""
5
6 # 1. Build the prompt (POM or text)
7 prompt = self._build_prompt()
8
9 # 2. Collect all SWAIG functions
10 functions = self._tool_registry.get_functions()
11
12 # 3. Generate webhook URLs with security tokens
13 webhook_url = self._build_webhook_url("/swaig")
14
15 # 4. Assemble AI configuration
16 ai_config = {
17 "prompt": prompt,
18 "post_prompt": self._post_prompt,
19 "post_prompt_url": self._build_webhook_url("/post_prompt"),
20 "SWAIG": {
21 "defaults": {"web_hook_url": webhook_url},
22 "functions": functions
23 },
24 "hints": self._hints,
25 "languages": self._languages,
26 "params": self._params
27 }
28
29 # 5. Build complete SWML document
30 swml = {
31 "version": "1.0.0",
32 "sections": {
33 "main": [
34 {"answer": {}},
35 {"ai": ai_config}
36 ]
37 }
38 }
39
40 return swml

Phase 3: AI Conversation

Once SignalWire has the SWML, it executes the instructions:

AI Conversation Loop.
AI Conversation Loop

AI Parameters that control this loop:

ParameterDefaultPurpose
end_of_speech_timeout500msWait time after user stops speaking
attention_timeout15000msMax silence before AI prompts
inactivity_timeout30000msMax silence before ending call
barge_match_string-Words that immediately interrupt AI

Phase 4: Function Calls

When the AI needs to call a function:

SWAIG Function Call.
SWAIG Function Call

Phase 5: Call End

When the call ends, the post-prompt summary is sent:

Call Ending.
Call Ending

Handling Post-Prompt

Configure post-prompt handling in your agent:

1from signalwire_agents import AgentBase
2
3
4class MyAgent(AgentBase):
5 def __init__(self):
6 super().__init__(name="my-agent")
7
8 # Set the post-prompt instruction
9 self.set_post_prompt(
10 "Summarize this call including: "
11 "1) The caller's main question or issue "
12 "2) How it was resolved "
13 "3) Any follow-up actions needed"
14 )
15
16 # Or use structured post-prompt with JSON output
17 self.set_post_prompt_json({
18 "issue": "string - the caller's main issue",
19 "resolution": "string - how the issue was resolved",
20 "follow_up": "boolean - whether follow-up is needed",
21 "sentiment": "string - caller sentiment (positive/neutral/negative)"
22 })
23
24 def on_post_prompt(self, data):
25 """Handle the call summary."""
26 summary = data.get("post_prompt_data", {})
27 call_id = data.get("call_id")
28
29 # Log to your system
30 self.log_call_summary(call_id, summary)
31
32 # Update CRM
33 self.update_crm(data)

Request/Response Headers

SWML Request (GET or POST /)

1GET / HTTP/1.1
2Host: your-agent.com
3Authorization: Basic c2lnbmFsd2lyZTpwYXNzd29yZA==
4Accept: application/json
5X-Forwarded-For: signalwire-ip
6X-Forwarded-Proto: https

SWML Response

1HTTP/1.1 200 OK
2Content-Type: application/json
3
4{"version": "1.0.0", "sections": {...}}

SWAIG Request (POST /swaig)

1POST /swaig HTTP/1.1
2Host: your-agent.com
3Authorization: Basic c2lnbmFsd2lyZTpwYXNzd29yZA==
4Content-Type: application/json
5
6{"action": "swaig_action", "function": "...", ...}

SWAIG Response

1HTTP/1.1 200 OK
2Content-Type: application/json
3
4{"response": "...", "action": [...]}

Debugging the Lifecycle

View SWML Output

$## See what your agent returns
$curl -u signalwire:password http://localhost:3000/ | jq '.'
$
$## Using swaig-test
$swaig-test my_agent.py --dump-swml

Test Function Calls

$## Call a function directly
$swaig-test my_agent.py --exec get_balance --account_id 12345
$
$## With verbose output
$swaig-test my_agent.py --exec get_balance --account_id 12345 --verbose

Monitor Live Traffic

1from signalwire_agents import AgentBase
2
3
4class DebugAgent(AgentBase):
5 def __init__(self):
6 super().__init__(name="debug-agent")
7
8 def on_swml_request(self, request_data=None, callback_path=None, request=None):
9 """Called when SWML is requested."""
10 if request:
11 print(f"SWML requested from: {request.client.host}")
12 print(f"Headers: {dict(request.headers)}")
13
14 def on_swaig_request(self, function_name, args, raw_data):
15 """Called before each SWAIG function."""
16 print(f"Function called: {function_name}")
17 print(f"Arguments: {args}")
18 print(f"Call ID: {raw_data.get('call_id')}")

Error Handling

SWML Errors

If your agent can’t generate SWML:

1def _render_swml(self):
2 try:
3 return self._build_swml()
4 except Exception as e:
5 # Return minimal valid SWML
6 return {
7 "version": "1.0.0",
8 "sections": {
9 "main": [
10 {"answer": {}},
11 {"play": {"url": "https://example.com/error.mp3"}},
12 {"hangup": {}}
13 ]
14 }
15 }

SWAIG Errors

If a function fails:

1def get_balance(self, args, raw_data):
2 try:
3 balance = self.lookup_balance(args.get("account_id"))
4 return SwaigFunctionResult(f"Your balance is ${balance}")
5 except DatabaseError:
6 return SwaigFunctionResult(
7 "I'm having trouble accessing account information right now. "
8 "Please try again in a moment."
9 )
10 except Exception as e:
11 # Log the error but return user-friendly message
12 self.logger.error(f"Function error: {e}")
13 return SwaigFunctionResult(
14 "I encountered an unexpected error. "
15 "Let me transfer you to a representative."
16 )

Next Steps

Now that you understand the complete lifecycle, let’s look at how security works throughout this flow.