showcase/shell-docs/src/content/ag-ui/sdk/kotlin/overview.mdx
The AG-UI Kotlin SDK is a Kotlin Multiplatform library for building AI agent user interfaces that implement the Agent User Interaction Protocol (AG-UI). It provides real-time streaming communication between Kotlin applications and AI agents across Android, iOS, and JVM platforms. Note: This SDK is community contributed and maintained. Please reach out to mefinsf in the AG-UI Discord with any questions.
Add the SDK to your Gradle project:
dependencies {
// Complete SDK with all modules (recommended)
implementation("com.agui:kotlin-client:0.2.1")
}
The client module automatically includes both kotlin-core and kotlin-tools as dependencies, giving you access to the complete SDK functionality.
For advanced use cases where you only need specific modules:
dependencies {
// Core protocol types only (advanced)
implementation("com.agui:kotlin-core:0.2.1")
// Tools framework only (advanced)
implementation("com.agui:kotlin-tools:0.2.1")
}
The SDK follows a modular architecture with three main components:
High-level agent implementations and client infrastructure.
Learn more about the Client module →
Protocol types, events, and message definitions.
Learn more about the Core module →
Tool execution framework for extending agent capabilities.
Learn more about the Tools module →
| Platform | Status | Minimum Version |
|---|---|---|
| Android | ✅ Stable | API 26+ |
| iOS | ✅ Stable | iOS 13+ |
| JVM | ✅ Stable | Java 11+ |
// Create a stateless agent
val agent = AgUiAgent("https://your-agent-api.com/agent") {
bearerToken = "your-api-token"
systemPrompt = "You are a helpful AI assistant"
}
// Send a message and receive streaming responses
agent.sendMessage("What's the weather like?").collect { state ->
println("State updated: $state")
}
// Create a stateful agent for conversations
val chatAgent = StatefulAgUiAgent("https://your-agent-api.com/agent") {
bearerToken = "your-api-token"
systemPrompt = "You are a friendly conversational AI"
}
// Have a conversation with context
chatAgent.chat("Hello!").collect { /* ... */ }
chatAgent.chat("What's my name?").collect { state ->
// Agent remembers previous context
}
Chunked protocol events (TEXT_MESSAGE_CHUNK, TOOL_CALL_CHUNK) are automatically rewritten into
their corresponding start/content/end sequences, so Kotlin clients see the same structured events
as non-chunked streams.
Thinking telemetry (THINKING_* events) is surfaced alongside normal messages, allowing UIs to indicate
when an agent is reasoning internally before responding.
// Create an agent with client-side tools
val agent = agentWithTools(
url = "https://your-agent-api.com/agent",
toolRegistry = toolRegistry {
addTool(WeatherToolExecutor()) // Executes locally on client
addTool(CalculatorToolExecutor()) // Executes locally on client
}
) {
bearerToken = "your-api-token"
}
// Agent can request client-side tool execution during conversation
agent.sendMessage("What's 15% tip on $85.50?").collect { state ->
// Agent requests calculator tool, which runs locally on the client
}
Note: Tools registered with the SDK execute on the client device, not on the agent's server. This enables secure access to local device capabilities (location, camera, file system) while maintaining privacy and reducing server load.
The SDK supports multiple authentication methods:
// Bearer Token
AgUiAgent(url) {
bearerToken = "your-token"
}
// API Key
AgUiAgent(url) {
apiKey = "your-api-key"
}
// Basic Auth
AgUiAgent(url) {
basicAuth("username", "password")
}
agent.sendMessage("Hello").collect { state ->
state.errors.forEach { error ->
println("Error: ${error.message}")
}
}
// Access current state
val currentState = agent.currentState
println("Messages: ${currentState.messages.size}")
// Monitor state changes
agent.sendMessage("Hello").collect { state ->
println("Updated state: ${state.messages.last()}")
}
// RAW and CUSTOM protocol events are surfaced for inspection
state.rawEvents?.forEach { raw ->
println("Raw event from ${raw.source ?: "unknown"}: ${raw.event}")
}
state.customEvents?.forEach { custom ->
println("Custom event ${custom.name}: ${custom.value}")
}
// Thinking telemetry stream
state.thinking?.let { thinking ->
if (thinking.isThinking) {
val latest = thinking.messages.lastOrNull().orEmpty()
println("Agent is thinking: $latest")
} else if (thinking.messages.isNotEmpty()) {
println("Agent finished thinking: ${thinking.messages.joinToString()}")
}
}