Sending Text Messages to AI Agents
Overview
In addition to voice conversation, you can send text messages directly to the AI Agent during an active call. This allows for mixed-mode communication where users can both speak and type messages to the AI Assistant.
Method Signature
fun sendAIAssistantMessage(message: String)
Parameters
| Parameter | Type | Description |
|---|---|---|
message | String | The text message to send to the AI Assistant |
Basic Usage
// Send a text message to the AI Agent during an active call
telnyxClient.sendAIAssistantMessage("Hello, can you help me with my account?")
Complete Example
class AIConversationActivity : AppCompatActivity() {
private lateinit var messageInput: EditText
private lateinit var sendButton: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ai_conversation)
messageInput = findViewById(R.id.messageInput)
sendButton = findViewById(R.id.sendButton)
setupMessageSending()
}
private fun setupMessageSending() {
sendButton.setOnClickListener {
val message = messageInput.text.toString().trim()
if (message.isNotEmpty()) {
sendTextMessage(message)
messageInput.text.clear()
}
}
// Send on Enter key
messageInput.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEND) {
sendButton.performClick()
true
} else {
false
}
}
}
private fun sendTextMessage(message: String) {
try {
telnyxClient.sendAIAssistantMessage(message)
Log.d("AI", "Text message sent: $message")
} catch (e: Exception) {
Log.e("AI", "Failed to send text message: ${e.message}")
showError("Failed to send message")
}
}
}
Advanced Usage with Call State Checking
class AIMessageManager(private val telnyxClient: TelnyxClient) {
fun sendMessage(message: String): Boolean {
return if (isAICallActive()) {
telnyxClient.sendAIAssistantMessage(message)
true
} else {
Log.w("AI", "Cannot send message: No active AI call")
false
}
}
private fun isAICallActive(): Boolean {
return telnyxClient.calls.values.any { call ->
call.callState == CallState.ACTIVE
}
}
fun sendMessageWithConfirmation(message: String, callback: (Boolean) -> Unit) {
if (sendMessage(message)) {
// Listen for confirmation in transcript updates
listenForMessageConfirmation(message, callback)
} else {
callback(false)
}
}
private fun listenForMessageConfirmation(
sentMessage: String,
callback: (Boolean) -> Unit
) {
// Monitor transcript for the sent message appearing
lifecycleScope.launch {
telnyxClient.transcriptUpdateFlow.collect { transcript ->
val userMessages = transcript.filter {
it.role == TranscriptItem.ROLE_USER
}
if (userMessages.any { it.content.contains(sentMessage) }) {
callback(true)
}
}
}
}
}
UI Integration Example
class ConversationFragment : Fragment() {
private lateinit var binding: FragmentConversationBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentConversationBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupMessageInput()
setupTranscriptDisplay()
}
private fun setupMessageInput() {
binding.messageInput.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
binding.sendButton.isEnabled = !s.isNullOrBlank()
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})
binding.sendButton.setOnClickListener {
sendCurrentMessage()
}
}
private fun sendCurrentMessage() {
val message = binding.messageInput.text.toString().trim()
if (message.isNotEmpty()) {
// Show message as "sending" in UI
addPendingMessage(message)
// Send to AI Assistant
telnyxClient.sendAIAssistantMessage(message)
// Clear input
binding.messageInput.text.clear()
}
}
private fun addPendingMessage(message: String) {
// Add message to UI with "sending" indicator
// This will be replaced when transcript updates arrive
}
}
Message Types and Formatting
class AIMessageHelper {
fun sendQuestion(question: String) {
telnyxClient.sendAIAssistantMessage("Question: $question")
}
fun sendCommand(command: String) {
telnyxClient.sendAIAssistantMessage("Command: $command")
}
fun sendContextualMessage(message: String, context: Map<String, String>) {
val contextString = context.entries.joinToString(", ") { "${it.key}: ${it.value}" }
telnyxClient.sendAIAssistantMessage("$message [Context: $contextString]")
}
fun sendFormattedMessage(message: String, format: MessageFormat) {
val formattedMessage = when (format) {
MessageFormat.URGENT -> "URGENT: $message"
MessageFormat.QUESTION -> "❓ $message"
MessageFormat.FEEDBACK -> "💬 $message"
MessageFormat.PLAIN -> message
}
telnyxClient.sendAIAssistantMessage(formattedMessage)
}
}
enum class MessageFormat {
URGENT, QUESTION, FEEDBACK, PLAIN
}
Error Handling
private fun sendTextMessageWithErrorHandling(message: String) {
try {
// Check if we have an active AI call
val hasActiveCall = telnyxClient.calls.values.any {
it.callState == CallState.ACTIVE
}
if (!hasActiveCall) {
showError("No active AI conversation. Please start a call first.")
return
}
// Send the message
telnyxClient.sendAIAssistantMessage(message)
// Show success feedback
showMessageSent(message)
} catch (e: Exception) {
Log.e("AI", "Failed to send message: ${e.message}")
showError("Failed to send message: ${e.message}")
}
}
private fun showError(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
private fun showMessageSent(message: String) {
// Optional: Show brief confirmation
Log.d("AI", "Message sent successfully: $message")
}
Important Notes
- Active Call Required: You must have an active call established before sending text messages
- AI Assistant Only: The
sendAIAssistantMessagemethod is only available during AI Assistant conversations - Transcript Integration: Text messages sent this way will appear in transcript updates alongside spoken conversation
- Processing: The AI Agent will process and respond to text messages just like spoken input
- Mixed Communication: Users can seamlessly switch between voice and text communication
Best Practices
- Validate Input: Always check that messages are not empty before sending
- Check Call State: Verify an active AI call exists before sending messages
- User Feedback: Provide visual feedback when messages are sent
- Error Handling: Handle network errors and call state issues gracefully
- UI Updates: Update the conversation UI immediately for better user experience
Integration with Transcript Updates
Text messages will appear in the transcript flow:
lifecycleScope.launch {
telnyxClient.transcriptUpdateFlow.collect { transcript ->
transcript.forEach { item ->
when (item.role) {
TranscriptItem.ROLE_USER -> {
// This includes both spoken words and text messages
displayUserMessage(item.content, item.timestamp)
}
TranscriptItem.ROLE_ASSISTANT -> {
// AI responses to both voice and text
displayAssistantMessage(item.content, item.timestamp)
}
}
}
}
}
This feature enables rich conversational experiences where users can seamlessly switch between voice and text communication with the AI Assistant.