> ## Documentation Index
> Fetch the complete documentation index at: https://chatbase.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Streaming

> How to stream real-time responses from the Chatbase Android SDK using callbacks and Kotlin Flow.

## Two-Tier Streaming API

The SDK provides two levels of abstraction for streaming:

* **`sendMessage()`** — High-level API with a callback DSL. Handles tool calls automatically (up to 10 iterations). Recommended for most use cases.
* **`sendMessageStream()`** — Low-level API returning a `Flow<ChatStreamEvent>`. Tool calls are not handled automatically, giving you full control over event processing.

## sendMessage

`interface ChatbaseClient` — **Package:** `com.chatbase.sdk`

```kotlin theme={null}
suspend fun sendMessage(
    message: String,
    conversationId: String? = null,
    callbacks: StreamCallbacks.() -> Unit = {}
): ChatResponse
```

Sends a message, streams the response in real time, and automatically handles tool calls (up to 10 iterations). Returns the aggregated `ChatResponse` when the stream completes.

**message** `String` *required*

The user message to send to the AI agent.

**conversationId** `String?`

Continue an existing conversation. Omit to use `currentConversationId` or start a new one.

**callbacks** `StreamCallbacks.() -\> Unit`

Streaming callback DSL.

```kotlin theme={null}
val response = client.sendMessage("Tell me a story") {
    onStart {
        println("Stream started...")
    }
    onTextDelta { delta ->
        // Called for each text chunk — append to your UI
        print(delta)
    }
    onToolCall { toolCall ->
        println("Agent is calling: ${toolCall.toolName}")
    }
    onToolResult { result ->
        println("Tool result: ${result.outputAsString()}")
    }
    onFinish { response ->
        println("\nDone! Message ID: ${response.id}")
    }
    onError { error ->
        println("Error: ${error.message}")
    }
}
```

### StreamCallbacks

`class StreamCallbacks` — **Package:** `com.chatbase.sdk`

> [!TIP]
>
> All callbacks are invoked on `Dispatchers.Main` — it is safe to update UI directly from any callback without explicit dispatching.

```kotlin theme={null}
fun onStart(handler: () -> Unit)
```

Called when the connection opens and streaming begins.

```kotlin theme={null}
fun onTextDelta(handler: (text: String) -> Unit)
```

Called for each incremental text chunk received.

```kotlin theme={null}
fun onToolCall(handler: (toolCall: ToolCallInfo) -> Unit)
```

Called when a tool call's full input is available (before execution).

```kotlin theme={null}
fun onToolResult(handler: (result: ToolResultInfo) -> Unit)
```

Called after a tool handler executes and returns a result.

```kotlin theme={null}
fun onFinish(handler: (response: ChatResponse) -> Unit)
```

Called when the stream completes successfully.

```kotlin theme={null}
fun onError(handler: (error: ChatbaseException) -> Unit)
```

Called when an error occurs during streaming.

### ChatResponse

`data class ChatResponse` — **Package:** `com.chatbase.sdk.model`

The aggregated result after streaming completes.

**id** `String` *required*

Server-assigned message ID.

**role** `String` *required*

Always `"assistant"`.

**parts** `List\<Part\>` *required*

The response content — text, tool calls, and tool results. See [ChatResponse](https://chatbase.co/docs/android-sdk/chat-response.md).

**metadata** `ResponseMetadata` *required*

**properties**

**messageId** `String?`

Same as `ChatResponse.id`.

**userMessageId** `String?`

Server-assigned ID for the user's message.

**conversationId** `String?`

The conversation ID. Pass this to continue the conversation.

**finishReason** `FinishReason`

Why the stream ended: `STOP`, `ERROR`, `TOOL_CALLS`, or `UNKNOWN`.

**usage** `Usage?`

**properties**

**credits** `Double`

Credits consumed by this request.

## sendMessageStream

```kotlin theme={null}
fun sendMessageStream(
    message: String,
    conversationId: String? = null
): Flow<ChatStreamEvent>
```

Returns a cold `Flow` of raw streaming events. Tool calls are **not** handled in Flow mode — registered tool handlers are not invoked, and the SDK exposes no API for submitting tool results manually.

**message** `String` *required*

The user message to send to the AI agent.

**conversationId** `String?`

Continue an existing conversation. Omit to use `currentConversationId` or start a new one.

> [!WARNING]
>
> Tool calls are **not** executed in Flow mode — tool events are informational only, and the stream finishes with `finishReason == "tool-calls"` without a final answer. If your AI agent uses client-side tools, use `sendMessage` with callbacks instead. See [Client-Side Tools](https://chatbase.co/docs/android-sdk/client-side-tools.md) for details.

```kotlin theme={null}
client.sendMessageStream("Tell me about Kotlin").collect { event ->
    when (event) {
        is ChatStreamEvent.TextDelta -> print(event.delta)
        is ChatStreamEvent.Finish -> println("\nDone: ${event.finishReason}")
        is ChatStreamEvent.Error -> println("Error: ${event.exception.message}")
        else -> { /* handle other events as needed */ }
    }
}
```

You can also filter for specific event types:

```kotlin theme={null}
client.sendMessageStream("Hello")
    .filterIsInstance<ChatStreamEvent.TextDelta>()
    .collect { event -> print(event.delta) }
```

## Stream Events

The `Flow` returned by `sendMessageStream` emits `ChatStreamEvent` objects — text deltas, tool input/output, step lifecycle, and errors. See [Streaming Events](https://chatbase.co/docs/android-sdk/streaming-events.md) for the full type reference.

## Continuing a Conversation

The SDK automatically tracks the current conversation. After sending a message, subsequent calls reuse the same conversation:

```kotlin theme={null}
// First message — starts a new conversation
client.sendMessage("My name is Alice.")
println(client.currentConversationId) // "conv_abc123"

// Subsequent messages continue the same conversation
client.sendMessage("What is my name?") // Agent remembers: "Alice"
```

To start a fresh conversation:

```kotlin theme={null}
client.newConversation()
client.sendMessage("Fresh start!") // Creates a new conversation
```

> [!TIP]
>
> See [Conversations & History](https://chatbase.co/docs/android-sdk/conversations.md) for listing conversations and loading message history.

## retry

```kotlin theme={null}
suspend fun retry(
    conversationId: String,
    messageId: String,
    callbacks: StreamCallbacks.() -> Unit = {}
): ChatResponse
```

Retry a failed assistant message. Same streaming and tool-loop behavior as `sendMessage`.

**conversationId** `String` *required*

The conversation containing the failed message.

**messageId** `String` *required*

The ID of the assistant message to retry.

**callbacks** `StreamCallbacks.() -\> Unit`

Streaming callback DSL.

A convenience extension extracts the IDs from a `ChatResponse`:

```kotlin theme={null}
suspend fun ChatbaseClient.retry(
    response: ChatResponse,
    callbacks: StreamCallbacks.() -> Unit = {}
): ChatResponse
```

```kotlin theme={null}
val response = client.sendMessage("Hello")
// ... later:
val retried = client.retry(response) {
    onTextDelta { delta -> print(delta) }
}
```

## retryStream

```kotlin theme={null}
fun retryStream(
    conversationId: String,
    messageId: String
): Flow<ChatStreamEvent>
```

Raw streaming variant of `retry`. Tool calls are **not** handled automatically.

```kotlin theme={null}
client.retryStream(conversationId, messageId).collect { event ->
    when (event) {
        is ChatStreamEvent.TextDelta -> print(event.delta)
        is ChatStreamEvent.Finish -> println("\nDone")
        is ChatStreamEvent.Error -> println("Error: ${event.exception.message}")
        else -> {}
    }
}
```

## Related

> **[Client-Side Tools](https://chatbase.co/docs/android-sdk/client-side-tools.md)**
>
> Register tool handlers the AI agent can invoke

> **[Error Handling](https://chatbase.co/docs/android-sdk/error-handling.md)**
>
> Exception hierarchy and error handling patterns


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.