> 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 Kotlin

> **Info**
>
> Consulta la [panoramica di ElevenAgents](/docs/it/eleven-agents/overview) per una spiegazione di come
> funziona ElevenAgents.

## Installazione

Aggiungi l'SDK ElevenLabs al tuo progetto Android includendo la seguente dipendenza nel file `build.gradle` a livello di 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**
>
> Puoi trovare un'app Android di esempio che usa questo SDK
> [qui](https://github.com/elevenlabs/elevenlabs-android/tree/main/example-app)

## Requisiti

* Livello API Android 21 (Android 5.0) o superiore
* Autorizzazione Internet per le chiamate API
* Autorizzazione del microfono per l'input vocale
* Configurazione della sicurezza di rete per le chiamate HTTPS

## Configurazione

### Configurazione del manifest

Aggiungi le autorizzazioni necessarie al tuo `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" />
```

### Autorizzazioni di runtime

Per Android 6.0 (livello API 23) e versioni successive, devi richiedere l'autorizzazione del microfono in fase di runtime:

```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
            )
        }
    }
}
```

## Utilizzo

Inizializza l'SDK ElevenLabs nella classe `Application` o nell'attività principale:

Avvia una sessione di conversazione con una delle seguenti opzioni:

* Agente pubblico: passa `agentId`
* Agente privato: passa `conversationToken` fornito dal tuo backend (non esporre mai la tua chiave API al client).

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

Tieni presente che ElevenAgents richiede l'accesso al microfono. Prima dell'avvio della conversazione, valuta di spiegare e richiedere le autorizzazioni nell'interfaccia della tua app, soprattutto su Android 6.0+ dove sono richieste le autorizzazioni di runtime.

> **Note**
>
> Se uno strumento è configurato con `expects_response=false` sul server, restituisci `null` da `execute`
> per non inviare un risultato dello strumento all'agente.

## Agenti pubblici e privati

* **Agenti pubblici** (senza autenticazione): inizializza con `agentId` in `ConversationConfig`. L'SDK richiede un token di conversazione a ElevenLabs senza richiedere una chiave API sul dispositivo.
* **Agenti privati** (con autenticazione): inizializza con `conversationToken` in `ConversationConfig`. Il tuo server richiede un token di conversazione a ElevenLabs usando la tua chiave API ElevenLabs.

> **Error**
>
> Non incorporare mai chiavi API nei client. Possono essere estratte facilmente e usate in modo dannoso.

## Strumenti client

Registra strumenti client per consentire all'agente di richiamare funzionalità locali sul 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 l'agente emette una `client_tool_call`, l'SDK esegue lo strumento corrispondente e risponde con un `client_tool_result`. Se lo strumento non è registrato, viene richiamato `onUnhandledClientToolCall` e viene restituito all'agente un risultato di errore, se è prevista una risposta.

### Panoramica dei callback

* **onConnect** - Chiamato quando viene stabilita la connessione WebRTC. Restituisce l'ID della conversazione.
* **onMessage** - Chiamato quando viene ricevuto un nuovo messaggio. Può trattarsi di trascrizioni provvisorie o finali della voce dell'utente, risposte prodotte dall'LLM o messaggi di debug. Fornisce l'origine (`"ai"` o `"user"`) e il messaggio JSON non elaborato.
* **onModeChange** - Chiamato quando cambia la modalità della conversazione. È utile per indicare se l'agente sta parlando (`"speaking"`) o ascoltando (`"listening"`).
* **onStatusChange** - Chiamato quando cambia lo stato della conversazione (`"connected"`, `"connecting"` o `"disconnected"`).
* **onCanSendFeedbackChange** - Chiamato quando cambia la possibilità di inviare feedback. Abilita o disabilita i pulsanti di feedback.
* **onUnhandledClientToolCall** - Chiamato quando l'agente richiede uno strumento client non registrato sul dispositivo.
* **onVadScore** - Chiamato quando cambia il punteggio del rilevamento dell'attività vocale. Intervallo da 0 a 1, dove valori più alti indicano una maggiore affidabilità della presenza di parlato.
* **onAudioAlignment** - Chiamato quando vengono ricevuti dati di allineamento audio, che forniscono informazioni temporali a livello di carattere per il parlato dell'agente.

> **Warning**
>
> Non tutti gli eventi client sono abilitati per impostazione predefinita per un agente. Se hai abilitato un callback ma
> non ricevi eventi, assicurati che il tuo agente ElevenLabs abbia abilitato l'evento corrispondente.
> Puoi farlo nella scheda "Advanced" delle impostazioni dell'agente nella dashboard di ElevenLabs.

### Metodi

#### startSession

Il metodo `startSession` avvia la connessione WebRTC e inizia a usare il microfono per comunicare con l'agente ElevenLabs Agents.

##### Agenti pubblici

Per gli agenti pubblici, ovvero gli agenti che non hanno l'autenticazione abilitata, è richiesto solo `agentId`. Puoi ottenere l'ID dell'agente tramite l'[interfaccia di ElevenLabs](https://elevenlabs.io/app/agents).

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

##### Agenti privati

Per gli agenti privati, devi passare un `conversationToken` ottenuto dall'API ElevenLabs. Per generare questo token è necessaria una chiave API ElevenLabs.

> **Tip**
>
> Il `conversationToken` è valido per 10 minuti.

```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);
});
```

Quindi, passa il token al metodo `startSession`. Tieni presente che per gli agenti privati è richiesto solo `conversationToken`.

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

Facoltativamente, puoi passare un ID utente per identificare l'utente nella conversazione. Può essere il tuo identificatore cliente. Verrà incluso nei dati di avvio della conversazione inviati al server.

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

#### endSession

Un metodo per terminare manualmente la conversazione. Il metodo disconnette e termina la conversazione.

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

#### sendUserMessage

Invia un messaggio di testo all'agente durante una conversazione attiva. Questo attiverà una risposta dell'agente.

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

#### sendContextualUpdate

Invia informazioni contestuali all'agente senza attivare una risposta.

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

#### sendFeedback

Fornisci feedback sulla qualità della conversazione. Questo aiuta a migliorare le prestazioni dell'agente. Usa `onCanSendFeedbackChange` per abilitare l'interfaccia con pollice su/giù quando è consentito inviare feedback.

```kotlin
// Positive feedback
session.sendFeedback(true)

// Negative feedback
session.sendFeedback(false)
```

#### sendUserActivity

Notifica all'agente l'attività dell'utente per evitare interruzioni. È utile quando l'utente sta usando attivamente l'app e l'agente dovrebbe smettere di parlare, ad esempio quando l'utente sta digitando in una chat.

L'agente smetterà di parlare per circa 2 secondi dopo aver ricevuto questo segnale.

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

#### getId

Ottieni l'ID della conversazione.

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

#### Attiva/disattiva audio

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

Osserva `session.isMuted` per aggiornare l'etichetta dell'interfaccia tra "Disattiva audio" e "Attiva audio".

### Proprietà

#### status

Ottieni lo stato attuale della conversazione.

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

## ProGuard / R8

Se riduci/offuschi il codice, assicurati che i modelli Gson e LiveKit vengano mantenuti. Esempi di regole, da adattare in base alle necessità:

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

## Risoluzione dei problemi

* Assicurati che l'autorizzazione del microfono sia concessa in fase di runtime
* Se la riconnessione si blocca, verifica che la tua app chiami `session.endSession()` e che avvii una nuova istanza di sessione prima di riconnettersi
* Per gli emulatori, verifica che le route di input/output audio funzionino; i dispositivi fisici tendono a comportarsi in modo più affidabile

## Implementazione di esempio

Per un'implementazione di esempio, consulta l'app di esempio nel [repository dell'SDK Android di ElevenLabs](https://github.com/elevenlabs/elevenlabs-android/tree/main/example-app). L'app mostra:

* Connessione/disconnessione con un tocco
* Indicatore di parlato/ascolto
* Pulsanti di feedback con abilitazione/disabilitazione dell'interfaccia
* Indicatore di digitazione tramite `sendUserActivity()`
* Messaggi contestuali e dell'utente da un input
* Pulsante per attivare/disattivare l'audio del microfono