Skip to contentSkip to navigationSkip to topbar
Page toolsOn this page
Looking for more inspiration?Visit the

Channels


Channels are the communication methods that connect customers to your agent. TAC integrates with Twilio communication channels — including Voice, SMS, WhatsApp, RCS, and Chat — each with its own transport mechanism but sharing a unified callback interface.

All channels deliver messages to your message-ready callback, so you can handle messages from any channel with the same function. The ConversationSession object includes the channel field ("voice", "sms", "whatsapp", "rcs", or "chat") so you can customize responses per channel.


TAC server routes

tac-server-routes page anchor

TAC registers the following endpoints on your server. All paths are defaults and can be customized in your server configuration.

EndpointMethodChannelPurpose
/twimlPOSTVoiceGenerates TwiML to connect incoming calls to Conversation Relay
/wsWebSocketVoiceStreams real-time audio through Conversation Relay
/conversation-relay-callbackPOSTVoiceHandles call state changes and handoff data
/webhookPOSTMessagingReceives incoming messages from Twilio Conversations (SMS, WhatsApp, RCS, Chat)
/ci-webhookPOSTReceives Conversation Intelligence events (optional)

The Voice channel handles phone calls using Conversation Relay, which manages speech-to-text and text-to-speech over a WebSocket connection. Your agent works with text messages rather than audio streams.

How Voice works

how-voice-works page anchor
  1. A caller dials your Twilio phone number.
  2. Twilio sends a webhook to your server's TwiML endpoint (/twiml).
  3. TAC responds with TwiML that connects the call to a Conversation Relay WebSocket.
  4. Conversation Relay transcribes the caller's speech and sends text to TAC over the WebSocket. TAC processes the message and delivers it to your on_message_ready callback.
  5. Your agent processes the text and sends a response through the Voice channel.
  6. Conversation Relay converts the text response to speech and plays it to the caller.

Configure the Voice channel

configure-the-voice-channel page anchor
PythonTypeScript
1
from tac.channels.voice import VoiceChannel, VoiceChannelConfig
2
3
voice_channel = VoiceChannel(
4
tac,
5
config=VoiceChannelConfig(
6
memory_mode="always",
7
),
8
)
PythonTypeScript
1
async def handle_message_ready(
2
message: str,
3
context: ConversationSession,
4
memory: TACMemoryResponse | None,
5
) -> str | None:
6
llm_response = await generate_response(message)
7
8
await voice_channel.send_response(
9
conversation_id=context.conversation_id,
10
response=llm_response,
11
)

When a user interrupts the agent during a Voice conversation (for example, by speaking while the agent is still talking), TAC calls the on_interrupt callback. Use this to cancel in-progress LLM generation or other operations.

PythonTypeScript
1
async def handle_interrupt(
2
context: ConversationSession,
3
interrupt_data,
4
) -> None:
5
# Cancel any pending operations for this conversation
6
await cancel_pending_operations(context.conversation_id)
7
8
tac.on_interrupt(handle_interrupt)

The SMS channel handles text-based messaging through Twilio's Conversation Orchestrator webhooks. When a user sends an SMS to your Twilio phone number, Conversation Orchestrator routes the message to your webhook endpoint, and TAC processes it into your on_message_ready callback.

Configure the SMS channel and send responses

configure-the-sms-channel-and-send-responses page anchor
PythonTypeScript
1
from tac.channels.sms import SMSChannel, SMSChannelConfig
2
3
sms_channel = SMSChannel(
4
tac,
5
config=SMSChannelConfig(
6
memory_mode="always",
7
),
8
)
9
10
async def handle_message_ready(
11
message: str,
12
context: ConversationSession,
13
memory: TACMemoryResponse | None,
14
) -> str | None:
15
llm_response = await generate_response(message)
16
17
await sms_channel.send_response(
18
conversation_id=context.conversation_id,
19
response=llm_response,
20
)

The WhatsApp channel handles messaging through Twilio's WhatsApp Business API. It uses the same webhook endpoint (/webhook) as SMS and follows the same messaging pattern.

Configure the WhatsApp channel

configure-the-whatsapp-channel page anchor

Set the TWILIO_WHATSAPP_NUMBER environment variable to your WhatsApp-enabled number (format: whatsapp:+1234567890).

PythonTypeScript
1
from tac.channels.whatsapp import WhatsAppChannel, WhatsAppChannelConfig
2
3
whatsapp_channel = WhatsAppChannel(
4
tac,
5
config=WhatsAppChannelConfig(
6
memory_mode="always",
7
),
8
)

The RCS channel handles Rich Communication Services messaging. It uses the same webhook endpoint (/webhook) as SMS and WhatsApp.

Configure the RCS channel

configure-the-rcs-channel page anchor

Set the TWILIO_RCS_SENDER_ID environment variable to your RCS Sender ID.

PythonTypeScript
1
from tac.channels.rcs import RCSChannel, RCSChannelConfig
2
3
rcs_channel = RCSChannel(
4
tac,
5
config=RCSChannelConfig(
6
memory_mode="always",
7
),
8
)

Unified callback pattern

unified-callback-pattern page anchor

All channels deliver messages to the same message-ready callback. Return the response string and TAC automatically routes it to the correct channel:

PythonTypeScript
1
async def handle_message_ready(
2
message: str,
3
context: ConversationSession,
4
memory: TACMemoryResponse | None,
5
) -> str | None:
6
llm_response = await generate_response(message)
7
return llm_response
8
9
tac.on_message_ready(handle_message_ready)

If you need per-channel behavior (for example, shorter responses for voice), check context.channel:

PythonTypeScript
1
async def handle_message_ready(
2
message: str,
3
context: ConversationSession,
4
memory: TACMemoryResponse | None,
5
) -> str | None:
6
if context.channel == "voice":
7
return await generate_response(message, max_tokens=100)
8
else:
9
return await generate_response(message)
10
11
tac.on_message_ready(handle_message_ready)

Memory retrieval per channel

memory-retrieval-per-channel page anchor

Memory retrieval behavior is controlled by the memory_mode setting on each channel's config:

  • Messaging channels (SMS, WhatsApp, RCS): Set memory_mode to "always" to retrieve memory with each incoming message, or "once" to retrieve only on the first message in a conversation.
  • Voice: Set memory_mode to "always" in the VoiceChannelConfig to retrieve memory for each utterance, or "once" for only the first utterance. Default is "never".

You can also retrieve memory on demand from within your callback:

PythonTypeScript
1
# Manual memory retrieval
2
memory = await tac.retrieve_memory(context, query="customer preferences")

Register a callback to handle conversation cleanup when a session ends:

PythonTypeScript
1
async def handle_conversation_ended(context: ConversationSession) -> None:
2
# Clean up resources for this conversation
3
conversation_history.pop(context.conversation_id, None)
4
5
tac.on_conversation_ended(handle_conversation_ended)