> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# SDK para Kotlin

> **Info**
>
> Consulte a [visão geral do ElevenAgents](/docs/pt/eleven-agents/overview) 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`**

```kotlin build.gradle.kts
dependencies {
    // ElevenLabs Agents SDK (Android)
    implementation("io.elevenlabs:elevenlabs-android:<latest>")

    // Kotlin coroutines, AndroidX, etc., as needed by your app
}
```

> **Tip**
>
> Um exemplo de app Android que usa este SDK está disponível
> [aqui](https://github.com/elevenlabs/elevenlabs-android/tree/main/example-app)

## 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`:

```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:

```kotlin
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).

```kotlin
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.

> **Note**
>
> 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.

> **Error**
>
> 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.

```kotlin
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.

> **Warning**
>
> 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](https://elevenlabs.io/app/agents).

```kotlin
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.

> **Tip**
>
> O `conversationToken` é válido por 10 minutos.

```typescript maxLines=0
// 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.

```kotlin

// 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.

```kotlin
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.

```kotlin
session.endSession()
```

#### sendUserMessage

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

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

#### sendContextualUpdate

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

```kotlin
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.

```kotlin
// 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.

```kotlin
session.sendUserActivity()
```

#### getId

Obtenha o ID da conversa.

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

#### Silenciar/reativar microfone

```kotlin
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.

```kotlin
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):

```proguard
-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](https://github.com/elevenlabs/elevenlabs-android/tree/main/example-app). 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