Skip to main content

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

ParameterTypeDescription
messageStringThe 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 sendAIAssistantMessage method 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

  1. Validate Input: Always check that messages are not empty before sending
  2. Check Call State: Verify an active AI call exists before sending messages
  3. User Feedback: Provide visual feedback when messages are sent
  4. Error Handling: Handle network errors and call state issues gracefully
  5. 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.