Repository navigation
feat(twilio): a flow can make the relay wait quietly while the caller is busy on their phone - #1492
Conversation
… is busy on their phone A phone flow that asks the caller to do something on their phone (check a text arrived, fill in a form it texted them) expects silence, but the idle prompts read it as a dead line: "Sorry, I didn't catch that." five seconds in, a hang-up some twenty-five seconds in, before the flow could say what was still due (a confirmation number). Two conversation states, read as each turn's reply comes in (a reply with nothing to say still updates them): - twilio_relay_quiet_wait: "true" while silence is expected. The idle watcher then says only a soft check-in (prompt quiet-wait-check-in, "I'm still here whenever you're ready.") each QuietWaitSeconds (60), and hangs up after MaxQuietWaitPrompts (4) of them; both settings can be set per agent. - twilio_relay_goodbye_on_silence: what is said as the session hangs up on a caller who stayed quiet, in place of the idle-goodbye prompt, and said even when IdleAsksAgain is off. Without either state the idle prompts are as before. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
✅ AegisCode Code Review Report: PassCounted: 6 Low. None of them blocks this change. Low · .../BotSharp.Plugin.Twilio/Models/ConversationRelayStates.cs:27 · Constant naming: Constant 'QuietWait' (line 27) is not UPPER_CASEConstant 'QuietWait' (line 27) is not UPPER_CASE Suggested fix: [Validated by static analysis] Rename 'QuietWait' to 'QUIET_WAIT' Low · .../BotSharp.Plugin.Twilio/Models/ConversationRelayStates.cs:34 · Constant naming: Constant 'GoodbyeOnSilence' (line 34) is not UPPER_CASEConstant 'GoodbyeOnSilence' (line 34) is not UPPER_CASE Suggested fix: [Validated by static analysis] Rename 'GoodbyeOnSilence' to 'GOODBYE_ON_SILENCE' Low · .../BotSharp.Plugin.Twilio/Services/ConversationRelaySession.cs:23 · Constant naming: Constant 'DefaultQuietWaitCheckInText' (line 23) is not UPPER_CASEConstant 'DefaultQuietWaitCheckInText' (line 23) is not UPPER_CASE Suggested fix: [Validated by static analysis] Rename 'DefaultQuietWaitCheckInText' to 'DEFAULT_QUIET_WAIT_CHECK_IN_TEXT' Low · .../BotSharp.Plugin.Twilio/Services/ConversationRelaySession.cs:861 · Line length: This line is 135 characters long; the maximum is 125This line is 135 characters long; the maximum is 125 Suggested fix: [Validated by static analysis] Wrap the line so that no line exceeds 125 characters Low · .../BotSharp.Plugin.Twilio/Services/ConversationRelaySession.cs:880 · Line length: This line is 137 characters long; the maximum is 125This line is 137 characters long; the maximum is 125 Suggested fix: [Validated by static analysis] Wrap the line so that no line exceeds 125 characters Low · .../BotSharp.Plugin.Twilio/Services/TwilioConversationProcessor.cs:172 · Line length: This line is 132 characters long; the maximum is 125This line is 132 characters long; the maximum is 125 Suggested fix: [Validated by static analysis] Wrap the line so that no line exceeds 125 characters |
There was a problem hiding this comment.
🟡 Changes recommended
The change still has an active issue because new quiet-wait timeout, state-transition, and custom-goodbye branches lack the requested fake-WebSocket test coverage.
1 open issue
What changed in this PR
Adds flow-controlled quiet waiting for Twilio ConversationRelay calls, allowing callers time to complete phone-based tasks without triggering normal idle prompts or premature hang-ups.
Changes:
- Adds global and per-agent quiet-wait timing and prompt-count settings.
- Propagates quiet-wait and custom goodbye states from conversation flows into session handling.
- Updates idle monitoring to issue soft check-ins and support flow-provided goodbye text.
| File | Description |
|---|---|
| src/Plugins/BotSharp.Plugin.Twilio/Settings/ConversationRelaySetting.cs | Defines quiet-wait defaults and per-agent setting resolution. |
| src/Plugins/BotSharp.Plugin.Twilio/Settings/ConversationRelayAgentSetting.cs | Adds nullable per-agent quiet-wait overrides. |
| src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioConversationProcessor.cs | Captures quiet-wait and silence-goodbye states on assistant replies. |
| src/Plugins/BotSharp.Plugin.Twilio/Services/ConversationRelaySession.cs | Implements quiet-wait idle prompts, timing, limits, and custom goodbye handling. |
| src/Plugins/BotSharp.Plugin.Twilio/Models/ConversationRelayStates.cs | Defines flow state keys for quiet waiting and silence goodbye text. |
| src/Plugins/BotSharp.Plugin.Twilio/Models/ConversationRelayLabels.cs | Updates idle-prompt documentation for quiet-wait check-ins. |
| src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs | Carries quiet-wait metadata between processing and session layers. |
Review effort: Lite
| if (_idlePrompts < (quietWait ? relay.MaxQuietWaitPrompts : relay.MaxIdlePrompts)) | ||
| { | ||
| _idlePrompts++; | ||
| askAgain = true; | ||
| activity = _activity; | ||
| question = relay.IdleAsksAgain && stage == 0 ? ConversationRelayLines.LastQuestion(_lastLine) : null; | ||
| question = !quietWait && relay.IdleAsksAgain && stage == 0 ? ConversationRelayLines.LastQuestion(_lastLine) : null; |

Why
A phone flow that asks the caller to do something on their phone (check that a text arrived, fill in a form it texted them) expects silence. The idle prompts read that silence as a dead line: "Sorry, I didn't catch that." five seconds in, then "Are you still there?", then a hang-up about twenty-five seconds in, before the flow could say what was still due, such as a confirmation number.
What
Two conversation states a flow sets, read as each turn's reply comes in (a reply with nothing to say still updates them, so a flow that answers the caller's asides with nothing keeps the wait):
twilio_relay_quiet_wait="true"quiet-wait-check-in, default "I'm still here whenever you're ready.") eachQuietWaitSeconds(default 60) and hangs up afterMaxQuietWaitPrompts(default 4) of them. No "say it again", no "Are you still there?".twilio_relay_goodbye_on_silence= textidle-goodbyeprompt, even whenIdleAsksAgainis off.QuietWaitSecondsandMaxQuietWaitPromptscan be set per agent (ConversationRelay:Agents). Without either state, the idle prompts work as before.Tests
Session tests over a fake WebSocket (not in the repo, which has no Twilio test project):
IdleAsksAgainoff.🤖 Generated with Claude Code