ChatController

class ChatController(backend: (ToolApprover) -> ChatBackend, scope: CoroutineScope, initialMessages: List<Message> = emptyList(), clock: () -> Long = System::currentTimeMillis, newId: () -> String = { UUID.randomUUID().toString() }, publishIntervalMs: Long = 32)(source)

Owns one conversation and drives a ChatBackend, the Kotlin counterpart of the AI SDK useChat() hook.

Beyond send/stop it supports a message queue (send while busy), reply versions (regenerate keeps the old answer as a branch) and checkpoints (rewind the conversation to an earlier turn).

Parameters

backend

resolved on every turn, so switching provider/model applies to the next message without losing the conversation. It receives the controller's ToolApprover, which surfaces approval requests in the UI until respondToApproval is called. Threading: call it from one thread and give it a scope on a single-threaded dispatcher — viewModelScope (main thread) is the intended setup. The controller keeps its in-flight turn in plain fields, so a multi-threaded dispatcher such as Dispatchers.Default would race.

scope

where turns run; collection happens on this scope's dispatcher (backends move their own I/O off the main thread).

publishIntervalMs

streamed deltas are coalesced and published at most this often (one frame by default), so a model emitting hundreds of tokens per second never recomposes the UI per token. Structural events (tool calls, part ends, errors) publish immediately. 0 publishes every event.

Constructors

Link copied to clipboard
constructor(backend: (ToolApprover) -> ChatBackend, scope: CoroutineScope, initialMessages: List<Message> = emptyList(), clock: () -> Long = System::currentTimeMillis, newId: () -> String = { UUID.randomUUID().toString() }, publishIntervalMs: Long = 32)

Properties

Link copied to clipboard
val state: StateFlow<ChatState>

Functions

Link copied to clipboard
Link copied to clipboard
fun load(messages: List<Message>)

Replace the conversation (e.g. when switching threads).

Link copied to clipboard

Ask again; the previous reply is kept as another version of the answer.

Link copied to clipboard
Link copied to clipboard
fun respondToApproval(toolCallId: String, decision: ToolDecision)

Answer a tool approval request with a reason or edited arguments.

fun respondToApproval(toolCallId: String, approved: Boolean)

Answer a tool approval request (AI Elements <Confirmation>).

Link copied to clipboard
fun respondToInput(requestId: String, response: InputResponse)
Link copied to clipboard
fun restoreCheckpoint(messageId: String)

Rewind the conversation to just after messageId (AI Elements <Checkpoint>); later messages are dropped.

Link copied to clipboard
fun selectVersion(messageId: String, index: Int)

Show another version of an assistant reply (AI Elements <Branch>).

Link copied to clipboard
fun send(text: String, attachments: List<FilePart> = emptyList(), data: List<DataPart> = emptyList()): Boolean

Send a user message (text and/or attachments, and data parts such as an A2UI action — DataPart.A2UI). While a reply is streaming the message is queued and sent when the turn finishes. Returns false only when there is nothing to send.

Link copied to clipboard

Send a queued prompt now (when idle), e.g. after the queue paused on stop/error.

Link copied to clipboard
fun stop()

Abort the in-flight turn, keeping whatever has streamed so far. Queued prompts pause.