Call Flow Customization

Control call flow with verb insertion points for pre-answer, post-answer, and post-AI actions.

View as MarkdownOpen in Claude

Understanding Call Flow

By default, AgentBase generates a simple call flow:

answer → ai

The SDK provides three insertion points to customize this flow:

PRE-ANSWER VERBS (call still ringing).
PRE-ANSWER VERBS (call still ringing)

Verb Insertion Methods

MethodPurposeCommon Uses
add_pre_answer_verb()Before answeringRingback, screening, routing
add_post_answer_verb()After answer, before AIAnnouncements, disclaimers
add_post_ai_verb()After AI endsCleanup, transfers, surveys

Pre-Answer Verbs

Pre-answer verbs run while the call is still ringing. Use them for:

  • Ringback tones: Play audio before answering
  • Call screening: Check caller ID or time
  • Conditional routing: Route based on variables
1#!/usr/bin/env python3
2from signalwire_agents import AgentBase
3
4
5class RingbackAgent(AgentBase):
6 """Agent that plays ringback tone before answering."""
7
8 def __init__(self):
9 super().__init__(name="ringback", port=3000)
10
11 # Play US ringback tone before answering
12 # IMPORTANT: auto_answer=False prevents play from answering the call
13 self.add_pre_answer_verb("play", {
14 "urls": ["ring:us"],
15 "auto_answer": False
16 })
17
18 # Configure AI
19 self.add_language("English", "en-US", "rime.spore")
20 self.prompt_add_section("Role", "You are a helpful assistant.")
21
22
23if __name__ == "__main__":
24 agent = RingbackAgent()
25 agent.run()

Generated SWML:

1{
2 "sections": {
3 "main": [
4 {"play": {"urls": ["ring:us"], "auto_answer": false}},
5 {"answer": {}},
6 {"ai": {...}}
7 ]
8 }
9}

Pre-Answer Safe Verbs

Only certain verbs can run before the call is answered:

VerbPre-Answer SafeNotes
playYes*Requires auto_answer: false
connectYes*Requires auto_answer: false
sleepYesWait for duration
setYesSet variables
requestYesHTTP request
switchYesVariable-based branching
condYesConditional branching
ifYesIf/then/else
evalYesEvaluate expressions
gotoYesJump to label
labelYesDefine jump target
hangupYesReject call
transferYesRoute elsewhere

*These verbs auto-answer by default. Set auto_answer: false for pre-answer use.

Available Ringback Tones

ToneDescription
ring:usUS ringback tone
ring:ukUK ringback tone
ring:itItalian ringback tone
ring:atAustrian ringback tone

Post-Answer Verbs

Post-answer verbs run after the call is connected but before the AI speaks:

1#!/usr/bin/env python3
2from signalwire_agents import AgentBase
3
4
5class WelcomeAgent(AgentBase):
6 """Agent that plays welcome message before AI."""
7
8 def __init__(self):
9 super().__init__(name="welcome", port=3000)
10
11 # Play welcome announcement
12 self.add_post_answer_verb("play", {
13 "url": "say:Thank you for calling Acme Corporation. "
14 "Your call may be recorded for quality assurance."
15 })
16
17 # Brief pause before AI speaks
18 self.add_post_answer_verb("sleep", {"time": 500})
19
20 # Configure AI
21 self.add_language("English", "en-US", "rime.spore")
22 self.prompt_add_section(
23 "Role",
24 "You are a customer service representative. "
25 "The caller has just heard the welcome message."
26 )
27
28
29if __name__ == "__main__":
30 agent = WelcomeAgent()
31 agent.run()

Generated SWML:

1{
2 "sections": {
3 "main": [
4 {"answer": {}},
5 {"play": {"url": "say:Thank you for calling..."}},
6 {"sleep": {"time": 500}},
7 {"ai": {...}}
8 ]
9 }
10}

Common Post-Answer Uses

Use CaseExample
Welcome message{"url": "say:Thank you for calling..."}
Legal disclaimer{"url": "say:This call may be recorded..."}
Hold music{"url": "https://example.com/hold.mp3"}
Pause{"time": 500} (milliseconds)
RecordingUse record_call=True in constructor

Post-AI Verbs

Post-AI verbs run after the AI conversation ends:

1#!/usr/bin/env python3
2from signalwire_agents import AgentBase
3
4
5class SurveyAgent(AgentBase):
6 """Agent that logs call outcome after conversation."""
7
8 def __init__(self):
9 super().__init__(name="survey", port=3000)
10
11 # Configure AI
12 self.add_language("English", "en-US", "rime.spore")
13 self.prompt_add_section("Role", "You are a support agent.")
14
15 # After AI ends, log the call and hang up
16 self.add_post_ai_verb("request", {
17 "url": "https://api.example.com/call-complete",
18 "method": "POST"
19 })
20 self.add_post_ai_verb("hangup", {})
21
22
23if __name__ == "__main__":
24 agent = SurveyAgent()
25 agent.run()

Common Post-AI Uses

Use CaseVerbExample
Clean disconnecthangup{}
Transfer to humantransfer{"dest": "tel:+15551234567"}
Post-call surveypromptDTMF collection
Log outcomerequestHTTP POST to API
Connect to queueenter_queue{"name": "support"}

Complete Example

Here’s an agent with all three insertion points:

1#!/usr/bin/env python3
2from signalwire_agents import AgentBase
3
4
5class CallFlowAgent(AgentBase):
6 """Agent demonstrating complete call flow customization."""
7
8 def __init__(self):
9 super().__init__(name="call-flow", port=3000)
10
11 # PRE-ANSWER: Ringback tone
12 self.add_pre_answer_verb("play", {
13 "urls": ["ring:us"],
14 "auto_answer": False
15 })
16
17 # POST-ANSWER: Welcome and disclaimer
18 self.add_post_answer_verb("play", {
19 "url": "say:Welcome to Acme Corporation."
20 })
21 self.add_post_answer_verb("play", {
22 "url": "say:This call may be recorded for quality assurance."
23 })
24 self.add_post_answer_verb("sleep", {"time": 500})
25
26 # Configure AI
27 self.add_language("English", "en-US", "rime.spore")
28 self.prompt_add_section(
29 "Role",
30 "You are a friendly customer service representative. "
31 "The caller has just heard the welcome message."
32 )
33 self.set_params({
34 "end_of_speech_timeout": 1000,
35 "attention_timeout": 10000
36 })
37
38 # POST-AI: Clean disconnect
39 self.add_post_ai_verb("hangup", {})
40
41
42if __name__ == "__main__":
43 agent = CallFlowAgent()
44 agent.run()

Generated SWML:

1{
2 "sections": {
3 "main": [
4 {"play": {"urls": ["ring:us"], "auto_answer": false}},
5 {"answer": {}},
6 {"play": {"url": "say:Welcome to Acme Corporation."}},
7 {"play": {"url": "say:This call may be recorded..."}},
8 {"sleep": {"time": 500}},
9 {"ai": {...}},
10 {"hangup": {}}
11 ]
12 }
13}

Controlling Answer Behavior

Disable Auto-Answer

Set auto_answer=False to prevent automatic answering:

1class ManualAnswerAgent(AgentBase):
2 def __init__(self):
3 # Disable auto-answer
4 super().__init__(name="manual", port=3000, auto_answer=False)
5
6 # Pre-answer: Play ringback
7 self.add_pre_answer_verb("play", {
8 "urls": ["ring:us"],
9 "auto_answer": False
10 })
11
12 # Note: Without auto_answer, the AI will start without
13 # explicitly answering. Use add_answer_verb() if you need
14 # to answer at a specific point.

Customize Answer Verb

Use add_answer_verb() to configure the answer verb:

1# Set max call duration to 1 hour
2agent.add_answer_verb({"max_duration": 3600})

Dynamic Call Flow

Modify call flow based on caller information using on_swml_request():

1class DynamicFlowAgent(AgentBase):
2 def __init__(self):
3 super().__init__(name="dynamic", port=3000)
4 self.add_language("English", "en-US", "rime.spore")
5 self.prompt_add_section("Role", "You are a receptionist.")
6
7 # VIP numbers get special treatment
8 self.vip_numbers = ["+15551234567", "+15559876543"]
9
10 def on_swml_request(self, request_data=None, callback_path=None, request=None):
11 call_data = (request_data or {}).get("call", {})
12 caller = call_data.get("from", "")
13
14 if caller in self.vip_numbers:
15 # VIP: No ringback, immediate welcome
16 self.clear_pre_answer_verbs()
17 self.add_post_answer_verb("play", {
18 "url": "say:Welcome back, valued customer!"
19 })
20 else:
21 # Regular caller: Ringback tone
22 self.add_pre_answer_verb("play", {
23 "urls": ["ring:us"],
24 "auto_answer": False
25 })

Clear Methods

Remove verbs from insertion points:

1agent.clear_pre_answer_verbs() # Remove all pre-answer verbs
2agent.clear_post_answer_verbs() # Remove all post-answer verbs
3agent.clear_post_ai_verbs() # Remove all post-AI verbs

Method Chaining

All verb insertion methods return self for chaining:

1agent = AgentBase(name="chained", port=3000)
2agent.add_pre_answer_verb("play", {"urls": ["ring:us"], "auto_answer": False}) \
3 .add_post_answer_verb("play", {"url": "say:Welcome"}) \
4 .add_post_answer_verb("sleep", {"time": 500}) \
5 .add_post_ai_verb("hangup", {})