SDK para Kotlin

SDK do ElevenAgents: implante agentes de voz interativos e personalizados em minutos para apps Android.

Consulte a visão geral do ElevenAgents para entender como o ElevenAgents funciona.

Instalação

Adicione o SDK da ElevenLabs ao seu projeto Android incluindo a seguinte dependência no arquivo build.gradle do seu app:

build.gradle.kts
dependencies {
// ElevenLabs Agents SDK (Android)
implementation("io.elevenlabs:elevenlabs-android:<latest>")
// Kotlin coroutines, AndroidX, etc., as needed by your app
}

Um exemplo de app Android que usa este SDK está disponível aqui

Requisitos

  • Nível 21 da API Android (Android 5.0) ou superior
  • Permissão de Internet para chamadas de API
  • Permissão de microfone para entrada de voz
  • Configuração de segurança de rede para chamadas HTTPS

Configuração

Configuração do Manifest

Adicione as permissões necessárias ao seu AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Permissões em tempo de execução

No Android 6.0 (nível 23 da API) e versões posteriores, você precisa solicitar a permissão de microfone em tempo de execução:

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
private fun requestMicrophonePermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
// Show explanation to the user
showPermissionExplanationDialog()
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.RECORD_AUDIO),
MICROPHONE_PERMISSION_REQUEST_CODE
)
}
}
}

Uso

Inicialize o SDK da ElevenLabs na sua classe Application ou atividade principal:

Inicie uma sessão de conversa com uma destas opções:

  • Agente público: informe agentId
  • Agente privado: informe o conversationToken provisionado pelo seu backend (nunca exponha sua chave de API ao cliente).
import io.elevenlabs.ConversationClient
import io.elevenlabs.ConversationConfig
import io.elevenlabs.ConversationSession
import io.elevenlabs.ClientTool
import io.elevenlabs.ClientToolResult
// Start a public agent session (token generated for you)
val config = ConversationConfig(
agentId = "<your_public_agent_id>", // OR conversationToken = "<token>"
userId = "your-user-id",
// Optional callbacks
onConnect = { conversationId ->
// Called when the conversation is connected and returns the conversation ID. You can access conversationId via session.getId() too
},
onMessage = { source, messageJson ->
// Raw JSON messages from data channel; useful for logging/telemetry
},
onModeChange = { mode ->
// "speaking" | "listening" — drive UI indicators
},
onStatusChange = { status ->
// "connected" | "connecting" | "disconnected"
},
onCanSendFeedbackChange = { canSend ->
// Enable/disable thumbs up/down buttons for feedback reporting
},
onUnhandledClientToolCall = { call ->
// Agent requested a client tool not registered on the device
},
onVadScore = { score ->
// Voice Activity Detection score, range from 0 to 1 where higher values indicate higher confidence of speech
},
onAudioAlignment = { alignment ->
// Character-level timing data for synchronized text display
val chars = alignment["chars"] as? List<*>
val startTimes = alignment["char_start_times_ms"] as? List<*>
val durations = alignment["char_durations_ms"] as? List<*>
Log.d("ExampleApp", "Audio alignment: $chars")
},
// List of client tools the agent can invoke
clientTools = mapOf(
"logMessage" to object : ClientTool {
override suspend fun execute(parameters: Map<String, Any>): ClientToolResult {
val message = parameters["message"] as? String
Log.d("ExampleApp", "[INFO] Client Tool Log: $message")
return ClientToolResult.success("Message logged successfully")
}
}
),
)
// In an Activity context
val session: ConversationSession = ConversationClient.startSession(config, this)

O ElevenAgents requer acesso ao microfone. Considere explicar e solicitar permissões na interface do seu app antes do início da conversa, especialmente no Android 6.0+ , em que permissões em tempo de execução são necessárias.

Se uma ferramenta estiver configurada com expects_response=false no servidor, retorne null de execute para não enviar o resultado da ferramenta de volta ao agente.

Agentes públicos vs. privados

  • Agentes públicos (sem autenticação): inicialize com agentId em ConversationConfig. O SDK solicita um token de conversa à ElevenLabs sem precisar de uma chave de API no dispositivo.
  • Agentes privados (com autenticação): inicialize com conversationToken em ConversationConfig. Seu servidor solicita um token de conversa à ElevenLabs usando sua chave de API da ElevenLabs.
Nunca inclua chaves de API nos clientes. Elas podem ser extraídas facilmente e usadas de forma maliciosa.

Ferramentas do cliente

Registre ferramentas do cliente para permitir que o agente chame recursos locais no dispositivo.

val config = ConversationConfig(
agentId = "<public_agent>",
clientTools = mapOf(
"logMessage" to object : io.elevenlabs.ClientTool {
override suspend fun execute(parameters: Map<String, Any>): io.elevenlabs.ClientToolResult? {
val message = parameters["message"] as? String ?: return io.elevenlabs.ClientToolResult.failure("Missing 'message'")
android.util.Log.d("ClientTool", "Log: $message")
return null // No response needed for fire-and-forget tools
}
}
)
)

Quando o agente emite uma client_tool_call, o SDK executa a ferramenta correspondente e responde com um client_tool_result. Se a ferramenta não estiver registrada, onUnhandledClientToolCall será chamado e um resultado de falha será retornado ao agente (caso uma resposta seja esperada).

Visão geral dos callbacks

  • onConnect - Chamado quando a conexão WebRTC é estabelecida. Retorna o ID da conversa.
  • onMessage - Chamado quando uma nova mensagem é recebida. Podem ser transcrições provisórias ou finais da voz do usuário, respostas produzidas pelo LLM ou mensagens de depuração. Fornece a origem ("ai" ou "user") e a mensagem JSON bruta.
  • onModeChange - Chamado quando o modo da conversa muda. É útil para indicar se o agente está falando ("speaking") ou ouvindo ("listening").
  • onStatusChange - Chamado quando o status da conversa muda ("connected", "connecting" ou "disconnected").
  • onCanSendFeedbackChange - Chamado quando a possibilidade de enviar feedback muda. Ativa/desativa os botões de feedback.
  • onUnhandledClientToolCall - Chamado quando o agente solicita uma ferramenta do cliente que não está registrada no dispositivo.
  • onVadScore - Chamado quando a pontuação de detecção de atividade de voz muda. Varia de 0 a 1, e valores mais altos indicam maior confiança de fala.
  • onAudioAlignment - Chamado quando dados de alinhamento de áudio são recebidos, fornecendo informações de tempo em nível de caractere para a fala do agente.

Nem todos os eventos do cliente são ativados por padrão para um agente. Se você ativou um callback, mas não está recebendo eventos, verifique se o seu agente da ElevenLabs tem o evento correspondente ativado. Você pode fazer isso na aba “Advanced” das configurações do agente no painel da ElevenLabs.

Métodos

startSession

O método startSession inicia a conexão WebRTC e começa a usar o microfone para se comunicar com o agente do ElevenLabs Agents.

Agentes públicos

Para agentes públicos (ou seja, agentes sem autenticação ativada), apenas o agentId é necessário. O ID do agente pode ser obtido pela interface da ElevenLabs.

val session = ConversationClient.startSession(
config = ConversationConfig(
agentId = "your-agent-id"
),
context = this
)
Agentes privados

Para agentes privados, você precisa informar um conversationToken obtido pela API da ElevenLabs. Gerar esse token requer uma chave de API da ElevenLabs.

O conversationToken é válido por 10 minutos.
// Server-side token generation (Node.js example)
app.get("/conversation-token", yourAuthMiddleware, async (req, res) => {
const response = await fetch(
`https://api.elevenlabs.io/v1/convai/conversation/token?agent_id=${process.env.AGENT_ID}`,
{
headers: {
// Requesting a conversation token requires your ElevenLabs API key
// Do NOT expose your API key to the client!
"xi-api-key": process.env.ELEVENLABS_API_KEY,
},
}
);
if (!response.ok) {
return res.status(500).send("Failed to get conversation token");
}
const body = await response.json();
res.send(body.token);
});

Em seguida, passe o token ao método startSession. Observe que apenas o conversationToken é necessário para agentes privados.

// Get conversation token from your server
val conversationToken = fetchConversationTokenFromServer()
// For private agents, pass in the conversation token
val session = ConversationClient.startSession(
config = ConversationConfig(
conversationToken = conversationToken
),
context = this
)

Opcionalmente, você pode informar um ID de usuário para identificá-lo na conversa. Pode ser seu próprio identificador de cliente. Ele será incluído nos dados de início da conversa enviados ao servidor.

val session = ConversationClient.startSession(
config = ConversationConfig(
agentId = "your-agent-id",
userId = "your-user-id"
),
context = this
)

endSession

Um método para encerrar a conversa manualmente. O método desconecta e encerra a conversa.

session.endSession()

sendUserMessage

Envie uma mensagem de texto ao agente durante uma conversa ativa. Isso acionará uma resposta do agente.

session.sendUserMessage("Hello, how can you help me?")

sendContextualUpdate

Envia informações contextuais ao agente que não acionam uma resposta.

session.sendContextualUpdate(
"User navigated to the profile page. Consider this for next response."
)

sendFeedback

Forneça feedback sobre a qualidade da conversa. Isso ajuda a melhorar o desempenho do agente. Use onCanSendFeedbackChange para ativar sua interface de botões de gostei/não gostei quando o feedback for permitido.

// Positive feedback
session.sendFeedback(true)
// Negative feedback
session.sendFeedback(false)

sendUserActivity

Notifica o agente sobre a atividade do usuário para evitar interrupções. Útil quando o usuário está usando o app ativamente e o agente deve pausar a fala, por exemplo, quando o usuário está digitando em um chat.

O agente pausará a fala por cerca de 2 segundos depois de receber esse sinal.

session.sendUserActivity()

getId

Obtenha o ID da conversa.

val conversationId = session.getId()
Log.d("Conversation", "Conversation ID: $conversationId")
// e.g., "conv_123"

Silenciar/reativar microfone

session.toggleMute()
session.setMicMuted(true) // mute
session.setMicMuted(false) // unmute

Observe session.isMuted para atualizar o rótulo da interface entre “Silenciar” e “Reativar microfone”.

Propriedades

status

Obtenha o status atual da conversa.

val status = session.status
Log.d("Conversation", "Current status: $status")
// Values: DISCONNECTED, CONNECTING, CONNECTED

ProGuard / R8

Se você reduzir/ofuscar o código, garanta que os modelos Gson e o LiveKit sejam mantidos. Exemplo de regras (ajuste conforme necessário):

-keep class io.elevenlabs.** { *; }
-keep class io.livekit.** { *; }
-keepattributes *Annotation*

Solução de problemas

  • Verifique se a permissão de microfone foi concedida em tempo de execução
  • Se a reconexão travar, verifique se seu app chama session.endSession() e se você inicia uma nova instância de sessão antes de reconectar
  • Em emuladores, verifique se as rotas de entrada/saída de áudio estão funcionando; dispositivos físicos tendem a se comportar de forma mais confiável

Exemplo de implementação

Para ver um exemplo de implementação, consulte o app de exemplo no repositório do SDK Android da ElevenLabs. O app demonstra:

  • Conexão/desconexão com um toque
  • Indicador de fala/escuta
  • Botões de feedback com ativação/desativação na interface
  • Indicador de digitação por sendUserActivity()
  • Mensagens contextuais e do usuário a partir de uma entrada
  • Botão para silenciar/reativar o microfone