### Complete Ktor Server Example with ACP WebSocket Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/ktor-extensions.md A full example of a Ktor server setup including WebSocket configuration and ACP protocol integration. It demonstrates agent initialization and protocol startup. ```kotlin import io.ktor.server.application.* import io.ktor.server.auth.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.routing.* import io.ktor.server.websocket.* import com.agentclientprotocol.transport.acpProtocolOnServerWebSocket import com.agentclientprotocol.agent.Agent import com.agentclientprotocol.protocol.ProtocolOptions import com.agentclientprotocol.agent.AgentSupport import com.agentclientprotocol.agent.AgentSession import com.agentclientprotocol.client.ClientInfo import com.agentclientprotocol.common.SessionCreationParameters import com.agentclientprotocol.model.* import com.agentclientprotocol.common.Event import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.serialization.json.JsonElement import kotlin.time.Duration.Companion.seconds class SimpleAgentSupport : AgentSupport { override suspend fun initialize(clientInfo: ClientInfo): AgentInfo { return AgentInfo(LATEST_PROTOCOL_VERSION, AgentCapabilities()) } override suspend fun createSession(sessionParameters: SessionCreationParameters): AgentSession { return SimpleAgentSession() } } class SimpleAgentSession : AgentSession { override val sessionId = SessionId("session-" + System.currentTimeMillis()) override suspend fun prompt(content: List, _meta: JsonElement?): Flow = flow { emit(Event.SessionUpdateEvent( SessionUpdate.AgentMessageChunk(ContentBlock.Text("Hello from Ktor!")) )) emit(Event.PromptResponseEvent(PromptResponse(StopReason.END_TURN))) } override suspend fun cancel() {} } fun main() { embeddedServer(Netty, port = 8080) { install(WebSockets) { pingPeriod = 15.seconds timeout = 15.seconds maxFrameSize = Long.MAX_VALUE } acpProtocolOnServerWebSocket( path = "/acp", protocolOptions = ProtocolOptions(protocolDebugName = "ACP Server"), withAuth = null // TODO: Add proper auth ) { protocol -> val agent = Agent(protocol, SimpleAgentSupport()) protocol.start() } }.start(wait = true) } ``` -------------------------------- ### Protocol Setup Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Illustrates the setup and start of the Protocol, which is essential for communication between agent and client. ```APIDOC ## Protocol Setup ### Description Configure and start the `Protocol` instance to enable communication. This involves setting up the parent scope, transport, and optional protocol options. ### Usage ```kotlin val protocol = Protocol( parentScope = this, transport = transport, options = ProtocolOptions() ) protocol.start() ``` ### See Also - [Protocol and Transport](api-reference/protocol-and-transport.md#protocol) ``` -------------------------------- ### Agent Initialization Example Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/agent.md Demonstrates how to set up a transport, protocol, and an Agent instance with a custom AgentSupport implementation. It also shows how to start the protocol to begin listening for requests. ```kotlin import com.agentclientprotocol.agent.Agent import com.agentclientprotocol.agent.AgentSupport import com.agentclientprotocol.agent.AgentSession import com.agentclientprotocol.protocol.Protocol import com.agentclientprotocol.transport.StdioTransport import kotlinx.io.asSink import kotlinx.io.asSource import kotlinx.io.buffered import kotlinx.coroutines.runBlocking fun main(): Unit = runBlocking { val transport = StdioTransport( parentScope = this, input = System.`in`.asSource().buffered(), output = System.out.asSink().buffered() ) val protocol = Protocol(this, transport) // Create an agent with your AgentSupport implementation val agent = Agent( protocol = protocol, agentSupport = MyAgentSupport() ) // Start the protocol to begin listening protocol.start() } ``` -------------------------------- ### Setup Protocol with Options Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Initialize the Protocol with a parent scope, transport, and optional ProtocolOptions. The protocol must be started to enable communication. ```kotlin val protocol = Protocol( parentScope = this, transport = transport, options = ProtocolOptions() ) protocol.start() ``` -------------------------------- ### Minimal Client Setup with StdioTransport Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md Sets up a minimal client using StdioTransport. It initializes the client, starts the protocol, and creates a new session. ```kotlin val transport = StdioTransport(this, System.`in`.asSource().buffered(), System.out.asSink().buffered()) val protocol = Protocol(this, transport) val client = Client(protocol) protocol.start() client.initialize(ClientInfo(capabilities = ClientCapabilities())) val session = client.newSession( SessionCreationParameters("/home/user", emptyList()), MyOperationsFactory() ) ``` -------------------------------- ### Client Initialization Example Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md Example demonstrating how to create a ClientInfo object with specified file system and terminal capabilities, and then initialize the agent. ```kotlin val clientInfo = ClientInfo( capabilities = ClientCapabilities( fs = FileSystemCapability( readTextFile = true, writeTextFile = true ), terminal = TerminalCapability() ), implementation = Implementation( name = "MyClient", version = "1.0.0" ) ) val agentInfo = client.initialize(clientInfo) ``` -------------------------------- ### Agent Initialization Example Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md Example of how to initialize an agent, specifying its protocol version, capabilities, and implementation details. ```kotlin override suspend fun initialize(clientInfo: ClientInfo): return AgentInfo( protocolVersion = LATEST_PROTOCOL_VERSION, capabilities = AgentCapabilities( toolUse = AgentToolUseCapabilities( executeTools = true, progressSupport = true ) ), implementation = Implementation( name = "MyAgent", version = "1.0.0", title = "My Custom Agent" ) ) ``` -------------------------------- ### Complete Ktor Client Example Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/ktor-extensions.md Demonstrates a full Ktor client setup for connecting to an ACP WebSocket server, initializing a client, creating a session, and sending/receiving messages. ```kotlin import io.ktor.client.* import io.ktor.client.plugins.websocket.* import com.agentclientprotocol.transport.acpProtocolOnClientWebSocket import com.agentclientprotocol.client.Client import com.agentclientprotocol.client.ClientInfo import com.agentclientprotocol.client.ClientOperationsFactory import com.agentclientprotocol.common.ClientSessionOperations import com.agentclientprotocol.common.SessionCreationParameters import com.agentclientprotocol.model.* import kotlinx.coroutines.flow.collect import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.JsonElement import kotlin.time.Duration.Companion.seconds class DemoClientOperations : ClientSessionOperations { override suspend fun requestPermissions( toolCall: SessionUpdate.ToolCallUpdate, permissions: List, _meta: JsonElement? ) = RequestPermissionResponse( RequestPermissionOutcome.Selected(permissions.first().optionId) ) override suspend fun notify(notification: SessionUpdate, _meta: JsonElement?) { println("Received: $notification") } } suspend fun main() { val httpClient = HttpClient { install(WebSockets) { pingPeriod = 15.seconds timeout = 15.seconds maxFrameSize = Long.MAX_VALUE } } val protocol = httpClient.acpProtocolOnClientWebSocket( url = "ws://localhost:8080/acp", protocolOptions = ProtocolOptions(protocolDebugName = "ACP Client") ) protocol.start() val client = Client(protocol) val agentInfo = client.initialize(ClientInfo()) println("Connected to agent: ${agentInfo.implementation?.name}") val session = client.newSession( SessionCreationParameters( cwd = System.getProperty("user.dir"), mcpServers = emptyList() ), object : ClientOperationsFactory { override suspend fun createClientOperations( sessionId: SessionId, sessionResponse: AcpCreatedSessionResponse ): ClientSessionOperations { return DemoClientOperations() } } ) session.prompt(listOf(ContentBlock.Text("Hello, agent!"))).collect { event -> when (event) { is Event.SessionUpdateEvent -> println("Update: ${event.update}") is Event.PromptResponseEvent -> println("Response: ${event.response}") } } httpClient.close() } // Run with: runBlocking { main() } ``` -------------------------------- ### Client Initialization and Session Creation Example Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Demonstrates how to initialize a client with specific capabilities and create a new session using a custom ClientOperationsFactory. This example shows how to implement file system operations within the factory. ```kotlin val client = Client(protocol, null) client.initialize( ClientInfo( capabilities = ClientCapabilities( fs = FileSystemCapability(readTextFile = true, writeTextFile = true) ) ) ) val session = client.newSession( SessionCreationParameters(cwd = "/project"), object : ClientOperationsFactory { override suspend fun createClientOperations( sessionId: SessionId, sessionResponse: AcpCreatedSessionResponse ): ClientSessionOperations { return object : ClientSessionOperations, FileSystemOperations { override suspend fun requestPermissions( toolCall: SessionUpdate.ToolCallUpdate, permissions: List, _meta: JsonElement? ): RequestPermissionResponse { // Handle permission request return RequestPermissionResponse( RequestPermissionOutcome.Selected(permissions.first().optionId) ) } override suspend fun notify(notification: SessionUpdate, _meta: JsonElement?) { // Handle session updates println("Update: $notification") } override suspend fun fsReadTextFile( path: String, line: UInt?, limit: UInt?, _meta: JsonElement? ): ReadTextFileResponse { // Return file content return ReadTextFileResponse(...) } override suspend fun fsWriteTextFile( path: String, content: String, _meta: JsonElement? ): WriteTextFileResponse { // Handle file write return WriteTextFileResponse() } } } } ) ``` -------------------------------- ### Minimal Agent Setup with StdioTransport Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md Sets up a minimal agent using StdioTransport for communication. The protocol is started after agent initialization. ```kotlin val transport = StdioTransport(this, System.`in`.asSource().buffered(), System.out.asSink().buffered()) val protocol = Protocol(this, transport) Agent( protocol, MyAgentSupport() ) protocol.start() ``` -------------------------------- ### StdioTransport Usage Example Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/protocol-and-transport.md Demonstrates how to create and start a StdioTransport for local agent/client communication. Ensure the parent scope and streams are correctly provided. ```kotlin val transport = StdioTransport( parentScope = coroutineScope, input = System.`in`.asSource().buffered(), output = System.out.asSink().buffered() ) val protocol = Protocol(coroutineScope, transport) protocol.start() ``` -------------------------------- ### WebSocket Agent Setup (Ktor Server) Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md Configures and starts a WebSocket agent using Ktor's embedded server. It sets up the WebSocket endpoint and initializes the agent with the WebSocket transport. ```kotlin embeddedServer(Ktor.io.ktor.server.engine.Netty, port = 8080) { webSocket("/acp") { val transport = WebSocketTransport(this@launch, this) val protocol = Protocol(this@launch, transport) Agent(protocol, MyAgentSupport()) protocol.start() } }.start(wait = true) ``` -------------------------------- ### Kotlin Agent with STDIO and FileSystemOperations Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/README.md This snippet shows a complete example of a Kotlin agent. It sets up an AgentSupport, wires the STDIO transport, and demonstrates streaming responses. It also includes an example of calling the optional FileSystemOperations extension to read files. ```kotlin import com.agentclientprotocol.agent.Agent import com.agentclientprotocol.agent.AgentInfo import com.agentclientprotocol.agent.AgentSession import com.agentclientprotocol.agent.AgentSupport import com.agentclientprotocol.agent.clientInfo import com.agentclientprotocol.client.ClientInfo import com.agentclientprotocol.client.FileSystemOperations import com.agentclientprotocol.common.Event import com.agentclientprotocol.common.SessionParameters import com.agentclientprotocol.common.remoteSessionOperations import com.agentclientprotocol.model.AgentCapabilities import com.agentclientprotocol.model.ContentBlock import com.agentclientprotocol.model.LATEST_PROTOCOL_VERSION import com.agentclientprotocol.model.PromptResponse import com.agentclientprotocol.model.SessionId import com.agentclientprotocol.model.SessionUpdate import com.agentclientprotocol.model.StopReason import com.agentclientprotocol.protocol.Protocol import com.agentclientprotocol.transport.StdioTransport import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.JsonElement import kotlinx.io.asSink import kotlinx.io.asSource import kotlinx.io.buffered // 1. Build a dedicated AgentSession implementation for each connection. private class TerminalAgentSession( override val sessionId: SessionId ) : AgentSession { override suspend fun prompt( content: List, _meta: JsonElement? ): Flow = flow { // Echo back what the user typed. val userText = content.filterIsInstance().joinToString(" ") { it.text } emit( Event.SessionUpdateEvent( SessionUpdate.AgentMessageChunk(ContentBlock.Text("Agent heard: $userText")) ) ) // Optional extension call via the coroutine context. val context = currentCoroutineContext() val clientCapabilities = context.clientInfo.capabilities if (clientCapabilities.fs?.readTextFile == true) { val fs = context.remoteSessionOperations(FileSystemOperations) val readmeSnippet = fs.fsReadTextFile("README.md").content.take(120) emit( Event.SessionUpdateEvent( SessionUpdate.AgentMessageChunk(ContentBlock.Text("README preview: $readmeSnippet…")) ) ) } // Finish the turn once updates are sent. emit(Event.PromptResponseEvent(PromptResponse(StopReason.END_TURN))) } override suspend fun cancel() { // No long-running work in this demo, so nothing to clean up yet. } } // 2. Implement AgentSupport: negotiate capabilities and build per-session handlers. private class TerminalAgentSupport : AgentSupport { override suspend fun initialize(clientInfo: ClientInfo) = AgentInfo( protocolVersion = LATEST_PROTOCOL_VERSION, capabilities = AgentCapabilities() // advertise baseline agent features ) override suspend fun createSession(sessionParameters: SessionParameters): AgentSession { // 3. Instantiate the session implementation defined above. val sessionId = SessionId("session-${System.currentTimeMillis()}") return TerminalAgentSession(sessionId) } override suspend fun loadSession(sessionId: SessionId, sessionParameters: SessionParameters): AgentSession = // Rehydrate existing sessions with the provided identifier. TerminalAgentSession(sessionId) } fun main(): Unit = runBlocking { // 4. Bridge STDIO to the Protocol so the agent can speak ACP over stdin/stdout. val transport = StdioTransport( parentScope = this, input = System.`in`.asSource().buffered(), output = System.out.asSink().buffered() ) val protocol = Protocol(this, transport) // 5. Register the agent and declare which remote extensions it will use. Agent( protocol = protocol, agentSupport = TerminalAgentSupport(), remoteSideExtensions = listOf(FileSystemOperations) ) // 6. Start listening for messages from the client. protocol.start() } ``` -------------------------------- ### startNesSession Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Starts a new NES (Next Edit Suggestions) session. ```APIDOC ## startNesSession (UNSTABLE) ### Description Starts a new NES (Next Edit Suggestions) session. ### Method ```kotlin public suspend fun startNesSession( workspaceUri: String? = null, workspaceFolders: List? = null, repository: NesRepository? = null, _meta: JsonElement? = null ): ClientNesSession ``` ### Parameters #### Query Parameters - **workspaceUri** (String?) - Optional - Optional workspace URI - **workspaceFolders** (List?) - Optional - Optional workspace folders - **repository** (NesRepository?) - Optional - Optional repository information - **_meta** (JsonElement?) - Optional - Optional metadata ``` -------------------------------- ### Start NES Session in Kotlin Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Starts a new NES (Next Edit Suggestions) session. Use this to initiate a session focused on providing edit suggestions. ```kotlin @UnstableApi public suspend fun startNesSession( workspaceUri: String? = null, workspaceFolders: List? = null, repository: NesRepository? = null, _meta: JsonElement? = null ): ClientNesSession ``` -------------------------------- ### Run Kotlin ACP Client Sample Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/README.md Execute the sample project using Gradle. This command launches an end-to-end agent and client setup with STDIO transport. ```bash ./gradlew :samples:kotlin-acp-client-sample:run ``` -------------------------------- ### WebSocket Client Setup (Ktor Client) Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md Establishes a WebSocket connection using Ktor's HttpClient. It then initializes the ACP client with the WebSocket transport. ```kotlin val client = HttpClient { install(WebSockets) } client.webSocket("ws://localhost:8080/acp") { val transport = WebSocketTransport(this@runBlocking, this) val protocol = Protocol(this@runBlocking, transport) val client = Client(protocol) protocol.start() client.initialize(ClientInfo()) } ``` -------------------------------- ### Protocol Start Method Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/protocol-and-transport.md Connects to the transport and initiates message processing. This method must be invoked before sending any requests or notifications. ```kotlin public fun start() ``` -------------------------------- ### postInitialize Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/agent.md An optional lifecycle hook called after the session is initialized. This method can be used for post-initialization setup. ```APIDOC ## postInitialize ### Description Optional lifecycle hook called after the session is initialized. ### Method `suspend fun postInitialize()` ``` -------------------------------- ### Create Terminal Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md Creates and starts a new terminal with the given command and optional arguments, working directory, environment variables, and output byte limit. ```kotlin public suspend fun terminalCreate( command: String, args: List = emptyList(), cwd: String? = null, env: List = emptyList(), outputByteLimit: ULong? = null, _meta: JsonElement? = null ): CreateTerminalResponse ``` ```kotlin override suspend fun terminalCreate( command: String, args: List, cwd: String?, env: List, outputByteLimit: ULong?, _meta: JsonElement? ): CreateTerminalResponse { val processBuilder = ProcessBuilder(command, *args.toTypedArray()) if (cwd != null) processBuilder.directory(File(cwd)) val process = processBuilder.start() val terminalId = UUID.randomUUID().toString() terminals[terminalId] = process return CreateTerminalResponse(terminalId = terminalId) } ``` -------------------------------- ### STDIO Transport Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Provides an example of setting up the Standard Input/Output (STDIO) transport for communication. ```APIDOC ## STDIO Transport ### Description Configure the `StdioTransport` for communication using standard input and output streams. ### Usage ```kotlin val transport = StdioTransport( this, System.`in`.asSource().buffered(), System.out.asSink().buffered() ) ``` ### See Also - [Protocol and Transport](api-reference/protocol-and-transport.md#stdiotransport) ``` -------------------------------- ### Consume Messages from Channel Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/protocol-and-transport.md Example demonstrating how to consume messages from a transport converted to a message channel using a `for` loop. ```kotlin val messageChannel = transport.asMessageChannel() for (message in messageChannel) { // Process message } ``` -------------------------------- ### terminalCreate Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md Creates and starts a new terminal with the given command, arguments, working directory, environment variables, and optional output byte limit and metadata. ```APIDOC ## terminalCreate ### Description Creates and starts a new terminal with the given command. ### Method `public suspend fun` ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body - **command** (`String`) - Required - Command to execute - **args** (`List`) - Optional - Command arguments - **cwd** (`String?`) - Optional - Working directory - **env** (`List`) - Optional - Environment variables - **outputByteLimit** (`ULong?`) - Optional - Maximum output bytes to capture - **_meta** (`JsonElement?`) - Optional - Optional metadata ### Request Example ```kotlin // Example usage within the SDK // val response = agentClient.terminalCreate("ls", listOf("-l")) ``` ### Response #### Success Response - **CreateTerminalResponse** - Contains terminal ID and initial output. ``` -------------------------------- ### Minimal Client Implementation Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Implements basic client session operations for handling permission requests and notifications. This is a starting point for custom client logic. ```kotlin class MyOperations : ClientSessionOperations { override suspend fun requestPermissions( toolCall: SessionUpdate.ToolCallUpdate, permissions: List, _meta: JsonElement? ) = RequestPermissionResponse(RequestPermissionOutcome.Selected(permissions.first().optionId)) override suspend fun notify(notification: SessionUpdate, _meta: JsonElement?) { println("Agent: $notification") } } // Usage val client = Client(protocol) client.initialize(ClientInfo()) val session = client.newSession( SessionCreationParameters("/tmp", emptyList()), object : ClientOperationsFactory { override suspend fun createClientOperations( sessionId: SessionId, sessionResponse: AcpCreatedSessionResponse ) = MyOperations() } ) ``` -------------------------------- ### Implement requestPermissions in Kotlin Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md Example implementation for the `requestPermissions` method. This snippet demonstrates how to automatically grant the first available permission option when requested by the agent. ```kotlin override suspend fun requestPermissions( toolCall: SessionUpdate.ToolCallUpdate, permissions: List, _meta: JsonElement? ): RequestPermissionResponse { // Automatically grant the first option return RequestPermissionResponse( RequestPermissionOutcome.Selected(permissions.first().optionId) ) } ``` -------------------------------- ### Complete Kotlin SDK Client Operations Implementation Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md This snippet shows a full implementation of ClientSessionOperations, FileSystemOperations, and TerminalOperations. It includes methods for requesting permissions, handling notifications, reading and writing files, creating, managing, and releasing terminals, and waiting for terminal exit. The usage example demonstrates how to instantiate and use this client. ```kotlin import com.agentclientprotocol.client.* import com.agentclientprotocol.common.* import com.agentclientprotocol.model.* import kotlinx.serialization.json.JsonElement import java.io.File import java.util.* class MyClientOperations : ClientSessionOperations, FileSystemOperations, TerminalOperations { private val terminals = mutableMapOf() override suspend fun requestPermissions( toolCall: SessionUpdate.ToolCallUpdate, permissions: List, _meta: JsonElement? ): RequestPermissionResponse { // Auto-grant first permission for demo return RequestPermissionResponse( RequestPermissionOutcome.Selected(permissions.first().optionId) ) } override suspend fun notify(notification: SessionUpdate, _meta: JsonElement?) { println("Agent: $notification") } override suspend fun fsReadTextFile( path: String, line: UInt?, limit: UInt?, _meta: JsonElement? ): ReadTextFileResponse { var content = File(path).readText() if (limit != null) { content = content.take(limit.toInt()) } return ReadTextFileResponse(content) } override suspend fun fsWriteTextFile( path: String, content: String, _meta: JsonElement? ): WriteTextFileResponse { File(path).writeText(content) return WriteTextFileResponse() } override suspend fun terminalCreate( command: String, args: List, cwd: String?, env: List, outputByteLimit: ULong?, _meta: JsonElement? ): CreateTerminalResponse { val processBuilder = ProcessBuilder(listOf(command) + args) if (cwd != null) processBuilder.directory(File(cwd)) val process = processBuilder.start() val terminalId = UUID.randomUUID().toString() terminals[terminalId] = process return CreateTerminalResponse(terminalId) } override suspend fun terminalOutput( terminalId: String, _meta: JsonElement? ): TerminalOutputResponse { val process = terminals[terminalId] ?: return TerminalOutputResponse("") val output = process.inputStream.bufferedReader().readText() return TerminalOutputResponse(output) } override suspend fun terminalKill( terminalId: String, _meta: JsonElement? ): KillTerminalCommandResponse { terminals[terminalId]?.destroy() return KillTerminalCommandResponse() } override suspend fun terminalWaitForExit( terminalId: String, _meta: JsonElement? ): WaitForTerminalExitResponse { val exitCode = terminals[terminalId]?.waitFor() ?: 1 return WaitForTerminalExitResponse(exitCode.toUInt()) } override suspend fun terminalRelease( terminalId: String, _meta: JsonElement? ): ReleaseTerminalResponse { terminals.remove(terminalId)?.destroy() return ReleaseTerminalResponse() } } // Usage val client = Client(protocol) val session = client.newSession( SessionCreationParameters(cwd = "/project"), object : ClientOperationsFactory { override suspend fun createClientOperations( sessionId: SessionId, sessionResponse: AcpCreatedSessionResponse ): ClientSessionOperations { return MyClientOperations() } } ) ``` -------------------------------- ### List Sessions in Kotlin Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Lists all existing sessions. Returns a cold flow that lazily fetches pages. Use this to get an overview of active sessions. ```kotlin @UnstableApi public fun listSessions( cwd: String? = null, additionalDirectories: List? = null, _meta: JsonElement? = null ): Flow ``` -------------------------------- ### Implement notify in Kotlin Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md Example implementation for the `notify` method. This snippet shows how to handle different types of session updates received from the agent, such as message chunks, tool calls, and status updates. ```kotlin override suspend fun notify(notification: SessionUpdate, _meta: JsonElement?) { when (notification) { is SessionUpdate.AgentMessageChunk -> println("Agent: ${notification.content}") is SessionUpdate.ToolCall -> println("Tool call: ${notification.toolCall}") is SessionUpdate.ToolCallStatus -> println("Tool status: ${notification.status}") else -> println("Update: $notification") } } ``` -------------------------------- ### Implement fsReadTextFile in Kotlin Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md Example implementation for the `fsReadTextFile` method. This snippet demonstrates reading the entire content of a text file specified by a path. ```kotlin override suspend fun fsReadTextFile( path: String, line: UInt?, limit: UInt?, _meta: JsonElement? ): ReadTextFileResponse { val file = File(path) val content = file.readText() return ReadTextFileResponse(content) } ``` -------------------------------- ### Consume Agent Session Events Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/types.md Example of consuming events from an AgentSession.prompt() flow. Emits SessionUpdateEvent and PromptResponseEvent. ```kotlin override suspend fun prompt( content: List, _meta: JsonElement? ): Flow = flow { emit(Event.SessionUpdateEvent(SessionUpdate.AgentMessageChunk(ContentBlock.Text("Hello!")))) emit(Event.PromptResponseEvent(PromptResponse(StopReason.END_TURN))) } ``` -------------------------------- ### Example: ACP WebSocket Server without Authentication Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/ktor-extensions.md Shows how to configure an ACP WebSocket server without authentication. This is not recommended for production environments due to security risks. ```kotlin fun Application.configureAcp() { acpProtocolOnServerWebSocket( path = "/acp", protocolOptions = ProtocolOptions(), withAuth = null ) { protocol -> Agent(protocol, MyAgentSupport()) protocol.start() } } ``` -------------------------------- ### Example: ACP WebSocket Server with Authentication Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/ktor-extensions.md Demonstrates how to configure an ACP WebSocket server with JWT authentication. Ensure the 'jwt' authentication is properly set up in your Ktor application. ```kotlin import io.ktor.server.application.* import io.ktor.server.auth.* import io.ktor.server.websocket.* import com.agentclientprotocol.transport.acpProtocolOnServerWebSocket import com.agentclientprotocol.agent.Agent fun Application.configureAcp() { acpProtocolOnServerWebSocket( path = "/acp", protocolOptions = ProtocolOptions(), withAuth = { authBlock -> authenticate("jwt") { authBlock() } } ) { protocol -> Agent(protocol, MyAgentSupport()) protocol.start() } } ``` -------------------------------- ### acpProtocolOnClientWebSocket Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/ktor-extensions.md Creates a new ACP Protocol on a WebSocket via Ktor HttpClient. The protocol must be started manually by calling `protocol.start()`. ```APIDOC ## acpProtocolOnClientWebSocket ### Description Creates a new ACP Protocol on a WebSocket via Ktor HttpClient. The protocol must be started manually by calling `protocol.start()`. ### Method `suspend fun HttpClient.acpProtocolOnClientWebSocket( url: String = ACP_PATH, protocolOptions: ProtocolOptions, requestBuilder: HttpRequestBuilder.() -> Unit = {} ): Protocol ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```kotlin import io.ktor.client.* import io.ktor.client.plugins.websocket.* import com.agentclientprotocol.transport.acpProtocolOnClientWebSocket import com.agentclientprotocol.protocol.ProtocolOptions import com.agentclientprotocol.client.Client import com.agentclientprotocol.client.ClientInfo import com.agentclientprotocol.common.SessionCreationParameters import com.agentclientprotocol.client.ClientOperationsFactory val httpClient = HttpClient { install(WebSockets) } val protocol = httpClient.acpProtocolOnClientWebSocket( url = "/acp", protocolOptions = ProtocolOptions() ) { // Optional: configure HTTP request header("Authorization", "Bearer token") } protocol.start() val client = Client(protocol) client.initialize(ClientInfo()) val session = client.newSession( SessionCreationParameters("/project", emptyList()), MyOperationsFactory() ) ``` ### Response #### Success Response `Protocol` ready to start #### Response Example None explicitly provided, but returns a `Protocol` object. ### Throws Ktor client exceptions if connection fails ``` -------------------------------- ### Implement fsWriteTextFile in Kotlin Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md Example implementation for the `fsWriteTextFile` method. This snippet shows how to write provided content to a specified file path, overwriting any existing content. ```kotlin override suspend fun fsWriteTextFile( path: String, content: String, _meta: JsonElement? ): WriteTextFileResponse { File(path).writeText(content) return WriteTextFileResponse() } ``` -------------------------------- ### Creating a Client Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Shows how to initialize a Client instance, which is used for managing client-side connections and sessions. ```APIDOC ## Creating a Client ### Description Initialize a `Client` object to handle client-side connection management and session operations. ### Usage ```kotlin val protocol = Protocol(this, transport) val client = Client(protocol) ``` ### See Also - [Client API](api-reference/client.md#client) ``` -------------------------------- ### Run Gemini Interactive Kotlin Client Sample Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/README.md Launch the sample project with a specific main class to use an external Gemini ACP agent. This requires specifying the main class via a Gradle property. ```bash ./gradlew :samples:kotlin-acp-client-sample:run \ -PmainClass=com.agentclientprotocol.samples.client.GeminiClientAppKt ``` -------------------------------- ### Minimal Agent Implementation Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Demonstrates the basic structure for creating an agent using the Kotlin SDK. It includes implementing the AgentSupport interface for initialization and session creation, and a basic AgentSession for handling prompts. ```kotlin class MyAgent : AgentSupport { override suspend fun initialize(clientInfo: ClientInfo): AgentInfo { return AgentInfo(LATEST_PROTOCOL_VERSION, AgentCapabilities()) } override suspend fun createSession(params: SessionCreationParameters): AgentSession { return MyAgentSession() } } class MyAgentSession : AgentSession { override val sessionId = SessionId(UUID.randomUUID().toString()) override suspend fun prompt(content: List, _meta: JsonElement?): Flow = flow { emit(Event.SessionUpdateEvent(SessionUpdate.AgentMessageChunk(ContentBlock.Text("Hello!")))) emit(Event.PromptResponseEvent(PromptResponse(StopReason.END_TURN))) } override suspend fun cancel() {} } // Usage val protocol = Protocol(this, transport) Agent(protocol, MyAgent()) protocol.start() ``` -------------------------------- ### Get Terminal Output Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md Retrieves the current output from a running terminal using its ID. ```kotlin public suspend fun terminalOutput( terminalId: String, _meta: JsonElement? = null ): TerminalOutputResponse ``` -------------------------------- ### Creating an Agent Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Demonstrates how to create an Agent instance using the Protocol and AgentSupport. This is a fundamental step for agent-side operations. ```APIDOC ## Creating an Agent ### Description Instantiate an `Agent` object to manage agent-side logic and session interactions. ### Usage ```kotlin val protocol = Protocol(this, transport) val agent = Agent(protocol, agentSupport) ``` ### See Also - [Agent API](api-reference/agent.md#agent) ``` -------------------------------- ### Get Session in Kotlin Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Returns an existing session by ID. Use this to retrieve a specific session. ```kotlin public fun getSession(sessionId: SessionId): ClientSession ``` -------------------------------- ### Write First Kotlin Client Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/README.md This snippet shows how to implement a client session, handle file system operations, and process agent updates. It requires specific imports and defines custom session support. ```kotlin import com.agentclientprotocol.client.* import com.agentclientprotocol.common.ClientSessionOperations import com.agentclientprotocol.common.Event import com.agentclientprotocol.common.SessionParameters import com.agentclientprotocol.model.* import com.agentclientprotocol.protocol.Protocol import com.agentclientprotocol.transport.StdioTransport import kotlinx.coroutines.flow.collect import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.JsonElement import kotlinx.io.asSink import kotlinx.io.asSource import kotlinx.io.buffered import java.nio.file.Path import java.nio.file.Paths import kotlin.io.path.readText import kotlin.io.path.writeText // 1. Describe how the client should create session handlers for each connection. private class TerminalClientSupport(private val projectDir: Path) : ClientSupport { override suspend fun createClientSession( session: ClientSession, _sessionResponseMeta: JsonElement? ): ClientSessionOperations = TerminalSession(projectDir) } private class TerminalSession( private val projectDir: Path ) : ClientSessionOperations, FileSystemOperations { override suspend fun requestPermissions( toolCall: SessionUpdate.ToolCallUpdate, permissions: List, _meta: JsonElement? ): RequestPermissionResponse = // Grant whichever option was first in the list (swap for real UX). RequestPermissionResponse(RequestPermissionOutcome.Selected(permissions.first().optionId)) override suspend fun notify(notification: SessionUpdate, _meta: JsonElement?) { // Surface streaming updates back to the host application. println("Agent update: $notification") } override suspend fun fsReadTextFile( path: String, line: UInt?, limit: UInt?, _meta: JsonElement? ): ReadTextFileResponse = // Resolve file paths relative to the workspace root the client chose. ReadTextFileResponse(projectDir.resolve(path).readText()) override suspend fun fsWriteTextFile( path: String, content: String, _meta: JsonElement? ): WriteTextFileResponse { // Allow the agent to write files through the same extension API. projectDir.resolve(path).writeText(content) return WriteTextFileResponse() } } fun main(): Unit = runBlocking { val transport = StdioTransport( parentScope = this, input = System.`in`.asSource().buffered(), output = System.out.asSink().buffered() ) val protocol = Protocol(this, transport) val projectRoot = Paths.get("").toAbsolutePath() val client = Client( // 2. Register the client support and advertise which extensions you implement. protocol = protocol, clientSupport = TerminalClientSupport(projectRoot), handlerSideExtensions = listOf(FileSystemOperations) ) protocol.start() client.initialize( // 3. Negotiate capabilities so the agent knows extensions are available. ClientInfo( capabilities = ClientCapabilities( fs = FileSystemCapability(readTextFile = true, writeTextFile = true) ) ) ) val session = client.newSession( // 4. Launch a session pointing at the project workspace. SessionParameters( cwd = projectRoot.toString(), mcpServers = emptyList() ) ) session.prompt(listOf(ContentBlock.Text("Hello agent!"))).collect { when (event) { // 5. React to streaming updates and final responses. is Event.SessionUpdateEvent -> println("Agent update: ${event.update}") is Event.PromptResponseEvent -> println("Prompt finished: ${event.response.stopReason}") } } } ``` -------------------------------- ### Transport Send Method Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/protocol-and-transport.md Sends a JSON-RPC message over the transport. Ensure the transport is in a started state before sending. ```kotlin public fun send(message: JsonRpcMessage) ``` -------------------------------- ### Create Client Instance Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Instantiate the Client class with a Protocol. The transport must be configured prior to this step. ```kotlin val protocol = Protocol(this, transport) val client = Client(protocol) ``` -------------------------------- ### Create Agent Instance Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Instantiate the Agent class with a Protocol and AgentSupport implementation. Ensure the transport is correctly set up. ```kotlin val protocol = Protocol(this, transport) val agent = Agent(protocol, agentSupport) ``` -------------------------------- ### Get NES Session in Kotlin Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Returns an existing NES session by ID. Use this to retrieve a specific NES session. ```kotlin @UnstableApi public fun getNesSession(sessionId: SessionId): ClientNesSession ``` -------------------------------- ### Client Class Constructor Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Initializes a new Client instance. Requires a Protocol and optionally accepts a GlobalElicitationHandler for handling non-session elicitations. ```kotlin public class Client( public val protocol: Protocol, public val globalElicitationHandler: GlobalElicitationHandler? = null ) ``` -------------------------------- ### Configure STDIO Transport Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Set up the StdioTransport using System.in and System.out as the input and output streams, respectively. Buffering is applied for efficiency. ```kotlin val transport = StdioTransport( this, System.`in`.asSource().buffered(), System.out.asSink().buffered() ) ``` -------------------------------- ### Client Implementing Operations Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md On the client side, this demonstrates how to implement FileSystemOperations and TerminalOperations within a ClientOperationsFactory. All required methods must be implemented. ```kotlin object : ClientOperationsFactory { override suspend fun createClientOperations( sessionId: SessionId, sessionResponse: AcpCreatedSessionResponse ): ClientSessionOperations { return object : ClientSessionOperations, FileSystemOperations, TerminalOperations { // Implement all methods } } } ``` -------------------------------- ### initialize Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Initializes the client connection with the agent. This method must be called before creating any sessions. ```APIDOC ## initialize ### Description Initializes the client connection with the agent. This method must be called before creating any sessions. ### Method `suspend fun` ### Endpoint N/A (SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **clientInfo** (`ClientInfo`) - Required - Client information with capabilities - **_meta** (`JsonElement?`) - Optional - Optional metadata ### Returns `AgentInfo` containing agent capabilities and supported protocol version. ``` -------------------------------- ### SessionCreationParameters Configuration Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md Define parameters for creating or loading sessions, including current working directory, MCP servers, and additional directories. ```kotlin public class SessionCreationParameters( public val cwd: String, public val mcpServers: List, @property:UnstableApi public val additionalDirectories: List? = null, public val _meta: JsonElement? = null ) ``` ```kotlin val sessionParams = SessionCreationParameters( cwd = "/home/user/project", mcpServers = emptyList(), additionalDirectories = listOf("/home/user/docs") ) val session = client.newSession(sessionParams, operationsFactory) ``` -------------------------------- ### Initialize Client Connection Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Initializes the client connection with the agent. This method must be called before creating any sessions. It returns AgentInfo containing agent capabilities and supported protocol version. ```kotlin public suspend fun initialize( clientInfo: ClientInfo, _meta: JsonElement? = null ): AgentInfo ``` -------------------------------- ### FileSystemOperations.fsReadTextFile Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/extension-operations.md Reads text content from a specified file path. Supports optional parameters to start reading from a specific line and to limit the number of bytes read. ```APIDOC ## FileSystemOperations.fsReadTextFile ### Description Reads text content from a specified file path. Supports optional parameters to start reading from a specific line and to limit the number of bytes read. ### Method `suspend fun fsReadTextFile( path: String, line: UInt? = null, limit: UInt? = null, _meta: JsonElement? = null ): ReadTextFileResponse ``` -------------------------------- ### StdioTransport Configuration Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md Set up StdioTransport with buffered input and output streams. Requires a parent CoroutineScope. ```kotlin public class StdioTransport( parentScope: CoroutineScope, input: BufferedSource, output: BufferedSink, public val options: StdioTransportOptions = StdioTransportOptions() ) ``` ```kotlin import kotlinx.io.asSink import kotlinx.io.asSource import kotlinx.io.buffered val transport = StdioTransport( parentScope = coroutineScope, input = System.`in`.asSource().buffered(), output = System.out.asSink().buffered() ) ``` -------------------------------- ### AgentSupport initialize Method Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/agent.md Signature for the initialize method in AgentSupport, called upon client connection to handle initialization requests and return agent capabilities. ```kotlin public suspend fun initialize(clientInfo: ClientInfo): AgentInfo ``` -------------------------------- ### Client Constructor Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Initializes a new Client instance. This class is the main entry point for interacting with an ACP agent from the client side. ```APIDOC ## Client Constructor ### Description Initializes a new Client instance. This class is the main entry point for interacting with an ACP agent from the client side. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Constructor Signature ```kotlin public class Client( public val protocol: Protocol, public val globalElicitationHandler: GlobalElicitationHandler? = null ) ``` ### Parameters - **protocol** (`Protocol`) - Required - The protocol instance for communication - **globalElicitationHandler** (`GlobalElicitationHandler?`) - Optional - Optional handler for non-session elicitations (UNSTABLE) ``` -------------------------------- ### Create ACP Protocol on Ktor Client WebSocket Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/ktor-extensions.md Creates a new ACP Protocol instance on a WebSocket using Ktor HttpClient. The protocol requires manual starting after creation. It supports custom HTTP request configurations. ```kotlin public suspend fun HttpClient.acpProtocolOnClientWebSocket( url: String = ACP_PATH, protocolOptions: ProtocolOptions, requestBuilder: HttpRequestBuilder.() -> Unit = {} ): Protocol ``` ```kotlin import io.ktor.client.* import io.ktor.client.plugins.websocket.* import com.agentclientprotocol.transport.acpProtocolOnClientWebSocket import com.agentclientprotocol.protocol.ProtocolOptions import com.agentclientprotocol.client.Client import com.agentclientprotocol.client.ClientInfo import com.agentclientprotocol.common.SessionCreationParameters import com.agentclientprotocol.client.ClientOperationsFactory val httpClient = HttpClient { install(WebSockets) } val protocol = httpClient.acpProtocolOnClientWebSocket( url = "/acp", protocolOptions = ProtocolOptions() ) { // Optional: configure HTTP request header("Authorization", "Bearer token") } protocol.start() val client = Client(protocol) client.initialize(ClientInfo()) val session = client.newSession( SessionCreationParameters("/project", emptyList()), MyOperationsFactory() ) ``` -------------------------------- ### Agent Advertising FileSystemOperations Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/configuration.md On the agent side, this code snippet shows how to declare that the agent implements FileSystemOperations. This informs the client about the agent's capabilities. ```kotlin val agent = Agent( protocol = protocol, agentSupport = support, remoteSideExtensions = listOf(FileSystemOperations::class) ) ``` -------------------------------- ### ClientSession.prompt Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Sends a prompt to the agent and returns a flow of events. ```APIDOC ## ClientSession.prompt ### Description Sends a prompt to the agent and returns a flow of events. ### Method ```kotlin public suspend fun prompt( content: List ): Flow ``` ### Parameters #### Request Body - **content** (List) - Required - Content blocks to send ``` -------------------------------- ### AgentInfo Data Class Constructor Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/agent.md Represents agent capabilities and metadata returned during initialization. Includes protocol version, capabilities, authentication methods, and optional implementation details. ```kotlin public data class AgentInfo( val protocolVersion: ProtocolVersion, val capabilities: AgentCapabilities, val authMethods: List = emptyList(), val implementation: Implementation? = null, override val _meta: JsonElement? = null ) ``` -------------------------------- ### WebSocket Transport Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/INDEX.md Demonstrates how to set up a WebSocket transport for communication. ```APIDOC ## WebSocket Transport ### Description Initialize the `WebSocketTransport` for communication over a WebSocket connection. ### Usage ```kotlin val transport = WebSocketTransport(this, webSocketSession) ``` ### See Also - [Protocol and Transport](api-reference/protocol-and-transport.md#websockettransport) ``` -------------------------------- ### Create New Session Source: https://github.com/agentclientprotocol/kotlin-sdk/blob/master/_autodocs/api-reference/client.md Creates a new session with the agent, providing session parameters and an operations factory. Exceptions from the agent are propagated. ```kotlin public suspend fun newSession( sessionParameters: SessionCreationParameters, operationsFactory: ClientOperationsFactory ): ClientSession ```