diff --git a/acp-ktor-test/src/commonTest/kotlin/com/agentclientprotocol/SimpleAgentTest.kt b/acp-ktor-test/src/commonTest/kotlin/com/agentclientprotocol/SimpleAgentTest.kt index a0b7837..3674e7b 100644 --- a/acp-ktor-test/src/commonTest/kotlin/com/agentclientprotocol/SimpleAgentTest.kt +++ b/acp-ktor-test/src/commonTest/kotlin/com/agentclientprotocol/SimpleAgentTest.kt @@ -1649,7 +1649,7 @@ abstract class SimpleAgentTest(protocolDriver: ProtocolDriver) : ProtocolDriver ) } - override suspend fun listSessions(cwd: String?, _meta: kotlinx.serialization.json.JsonElement?): Sequence { + override suspend fun listSessions(cwd: String?, additionalDirectories: List?, _meta: kotlinx.serialization.json.JsonElement?): Sequence { return if (cwd != null) { testSessions.filter { it.cwd.contains(cwd) }.asSequence() } else { @@ -1700,7 +1700,7 @@ abstract class SimpleAgentTest(protocolDriver: ProtocolDriver) : ProtocolDriver ) } - override suspend fun listSessions(cwd: String?, _meta: kotlinx.serialization.json.JsonElement?): Sequence { + override suspend fun listSessions(cwd: String?, additionalDirectories: List?, _meta: kotlinx.serialization.json.JsonElement?): Sequence { return if (cwd != null) { testSessions.filter { it.cwd.contains(cwd) }.asSequence() } else { @@ -1729,6 +1729,63 @@ abstract class SimpleAgentTest(protocolDriver: ProtocolDriver) : ProtocolDriver assertTrue(filteredSessions.all { it.cwd.contains("/project/a") }) } + @OptIn(UnstableApi::class) + @Test + fun `list sessions filters by additionalDirectories`() = testWithProtocols { clientProtocol, agentProtocol -> + val testSessions = listOf( + SessionInfo(sessionId = SessionId("session-1"), cwd = "/project", additionalDirectories = listOf("/extra/a", "/extra/b")), + SessionInfo(sessionId = SessionId("session-2"), cwd = "/project", additionalDirectories = listOf("/extra/c")), + SessionInfo(sessionId = SessionId("session-3"), cwd = "/project", additionalDirectories = null), + ) + + var receivedAdditionalDirectories: List? = null + + val client = Client(protocol = clientProtocol) + val agent = Agent(protocol = agentProtocol, agentSupport = object : AgentSupport { + override suspend fun initialize(clientInfo: ClientInfo): AgentInfo { + return AgentInfo( + clientInfo.protocolVersion, + capabilities = AgentCapabilities( + sessionCapabilities = SessionCapabilities(list = SessionListCapabilities()) + ) + ) + } + + override suspend fun listSessions(cwd: String?, additionalDirectories: List?, _meta: kotlinx.serialization.json.JsonElement?): Sequence { + receivedAdditionalDirectories = additionalDirectories + return if (additionalDirectories != null) { + testSessions.filter { session -> + session.additionalDirectories != null && + additionalDirectories.all { it in session.additionalDirectories!! } + }.asSequence() + } else { + testSessions.asSequence() + } + } + + override suspend fun createSession(sessionParameters: SessionCreationParameters): AgentSession { + TODO("Not yet implemented") + } + + override suspend fun loadSession( + sessionId: SessionId, + sessionParameters: SessionCreationParameters, + ): AgentSession { + TODO("Not yet implemented") + } + }) + + client.initialize(ClientInfo(protocolVersion = LATEST_PROTOCOL_VERSION)) + + val filterDirs = listOf("/extra/a") + val flow = client.listSessions(additionalDirectories = filterDirs) + val filteredSessions = flow.toList() + + assertEquals(filterDirs, receivedAdditionalDirectories) + assertEquals(1, filteredSessions.size) + assertEquals("session-1", filteredSessions.first().sessionId.value) + } + @OptIn(UnstableApi::class) @Test fun `list sessions with partial iteration works correctly`() = testWithProtocols { clientProtocol, agentProtocol -> @@ -1748,7 +1805,7 @@ abstract class SimpleAgentTest(protocolDriver: ProtocolDriver) : ProtocolDriver ) } - override suspend fun listSessions(cwd: String?, _meta: JsonElement?): Sequence { + override suspend fun listSessions(cwd: String?, additionalDirectories: List?, _meta: JsonElement?): Sequence { // Return all sessions - the adapter will handle pagination return allSessions.asSequence() } @@ -1794,7 +1851,7 @@ abstract class SimpleAgentTest(protocolDriver: ProtocolDriver) : ProtocolDriver ) } - override suspend fun listSessions(cwd: String?, _meta: JsonElement?): Sequence { + override suspend fun listSessions(cwd: String?, additionalDirectories: List?, _meta: JsonElement?): Sequence { resourcesAcquired++ return sequence { @@ -1853,7 +1910,7 @@ abstract class SimpleAgentTest(protocolDriver: ProtocolDriver) : ProtocolDriver ) } - override suspend fun listSessions(cwd: String?, _meta: JsonElement?): Sequence { + override suspend fun listSessions(cwd: String?, additionalDirectories: List?, _meta: JsonElement?): Sequence { // The Agent's setPaginatedRequestHandler with batchSize=10 will consume // items from this sequence in batches of 10 return sequence { @@ -1909,7 +1966,7 @@ abstract class SimpleAgentTest(protocolDriver: ProtocolDriver) : ProtocolDriver ) } - override suspend fun listSessions(cwd: String?, _meta: JsonElement?): Sequence { + override suspend fun listSessions(cwd: String?, additionalDirectories: List?, _meta: JsonElement?): Sequence { fetchStarted = true return sequenceOf( SessionInfo(sessionId = SessionId("session-1"), cwd = "/project") diff --git a/acp-model/api/acp-model.api b/acp-model/api/acp-model.api index bbd1d9a..0e5e5bc 100644 --- a/acp-model/api/acp-model.api +++ b/acp-model/api/acp-model.api @@ -1908,14 +1908,16 @@ public final class com/agentclientprotocol/model/KillTerminalCommandResponse$Com public final class com/agentclientprotocol/model/ListSessionsRequest : com/agentclientprotocol/model/AcpPaginatedRequest, com/agentclientprotocol/model/AcpRequest { public static final field Companion Lcom/agentclientprotocol/model/ListSessionsRequest$Companion; public fun ()V - public fun (Ljava/lang/String;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;)V + public synthetic fun (Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Lkotlinx/serialization/json/JsonElement; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;)Lcom/agentclientprotocol/model/ListSessionsRequest; - public static synthetic fun copy$default (Lcom/agentclientprotocol/model/ListSessionsRequest;Ljava/lang/String;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;ILjava/lang/Object;)Lcom/agentclientprotocol/model/ListSessionsRequest; + public final fun component2 ()Ljava/util/List; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Lkotlinx/serialization/json/JsonElement; + public final fun copy (Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;)Lcom/agentclientprotocol/model/ListSessionsRequest; + public static synthetic fun copy$default (Lcom/agentclientprotocol/model/ListSessionsRequest;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;ILjava/lang/Object;)Lcom/agentclientprotocol/model/ListSessionsRequest; public fun equals (Ljava/lang/Object;)Z + public final fun getAdditionalDirectories ()Ljava/util/List; public fun getCursor ()Ljava/lang/String; public final fun getCwd ()Ljava/lang/String; public fun get_meta ()Lkotlinx/serialization/json/JsonElement; diff --git a/acp-model/src/commonMain/kotlin/com/agentclientprotocol/model/Requests.kt b/acp-model/src/commonMain/kotlin/com/agentclientprotocol/model/Requests.kt index ad5e1be..0ac0eaa 100644 --- a/acp-model/src/commonMain/kotlin/com/agentclientprotocol/model/Requests.kt +++ b/acp-model/src/commonMain/kotlin/com/agentclientprotocol/model/Requests.kt @@ -788,6 +788,7 @@ public data class ForkSessionResponse( @Serializable public data class ListSessionsRequest( val cwd: String? = null, + val additionalDirectories: List? = null, override val cursor: String? = null, override val _meta: JsonElement? = null ) : AcpRequest, AcpPaginatedRequest diff --git a/acp/api/acp.api b/acp/api/acp.api index d892e8e..e70433e 100644 --- a/acp/api/acp.api +++ b/acp/api/acp.api @@ -92,8 +92,8 @@ public abstract interface class com/agentclientprotocol/agent/AgentSupport { public fun forkSession-nk3TnMc (Ljava/lang/String;Lcom/agentclientprotocol/common/SessionCreationParameters;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun forkSession-nk3TnMc$suspendImpl (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Lcom/agentclientprotocol/common/SessionCreationParameters;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun initialize (Lcom/agentclientprotocol/client/ClientInfo;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public fun listSessions (Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static synthetic fun listSessions$suspendImpl (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun listSessions (Ljava/lang/String;Ljava/util/List;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun listSessions$suspendImpl (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Ljava/util/List;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun loadSession-nk3TnMc (Ljava/lang/String;Lcom/agentclientprotocol/common/SessionCreationParameters;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun loadSession-nk3TnMc$suspendImpl (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Lcom/agentclientprotocol/common/SessionCreationParameters;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun logout (Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -106,7 +106,7 @@ public final class com/agentclientprotocol/agent/AgentSupport$DefaultImpls { public static fun authenticate-fMnwWJU (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun createNesSession (Lcom/agentclientprotocol/agent/AgentSupport;Lcom/agentclientprotocol/model/StartNesRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun forkSession-nk3TnMc (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Lcom/agentclientprotocol/common/SessionCreationParameters;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static fun listSessions (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun listSessions (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Ljava/util/List;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun loadSession-nk3TnMc (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Lcom/agentclientprotocol/common/SessionCreationParameters;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun logout (Lcom/agentclientprotocol/agent/AgentSupport;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun resumeSession-nk3TnMc (Lcom/agentclientprotocol/agent/AgentSupport;Ljava/lang/String;Lcom/agentclientprotocol/common/SessionCreationParameters;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -162,8 +162,8 @@ public final class com/agentclientprotocol/client/Client { public final fun getSession-0izbxq0 (Ljava/lang/String;)Lcom/agentclientprotocol/client/ClientSession; public final fun initialize (Lcom/agentclientprotocol/client/ClientInfo;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun initialize$default (Lcom/agentclientprotocol/client/Client;Lcom/agentclientprotocol/client/ClientInfo;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; - public final fun listSessions (Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;)Lkotlinx/coroutines/flow/Flow; - public static synthetic fun listSessions$default (Lcom/agentclientprotocol/client/Client;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow; + public final fun listSessions (Ljava/lang/String;Ljava/util/List;Lkotlinx/serialization/json/JsonElement;)Lkotlinx/coroutines/flow/Flow; + public static synthetic fun listSessions$default (Lcom/agentclientprotocol/client/Client;Ljava/lang/String;Ljava/util/List;Lkotlinx/serialization/json/JsonElement;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow; public final fun loadSession-wPMwmcM (Ljava/lang/String;Lcom/agentclientprotocol/common/SessionCreationParameters;Lcom/agentclientprotocol/client/ClientOperationsFactory;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun logout (Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun logout$default (Lcom/agentclientprotocol/client/Client;Lkotlinx/serialization/json/JsonElement;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; diff --git a/acp/src/commonMain/kotlin/com/agentclientprotocol/agent/Agent.kt b/acp/src/commonMain/kotlin/com/agentclientprotocol/agent/Agent.kt index 15711e0..ec9744f 100644 --- a/acp/src/commonMain/kotlin/com/agentclientprotocol/agent/Agent.kt +++ b/acp/src/commonMain/kotlin/com/agentclientprotocol/agent/Agent.kt @@ -158,7 +158,7 @@ public class Agent( // TODO: move to some global agent/client settings batchSize = 10, batchedResultFactory = { _, batch, newCursor -> ListSessionsResponse(batch, newCursor) }, - sequenceFactory = { p -> agentSupport.listSessions(p.cwd, p._meta) } + sequenceFactory = { p -> agentSupport.listSessions(p.cwd, p.additionalDirectories, p._meta) } ) protocol.setRequestHandler(AcpMethod.AgentMethods.SessionNew) { params: NewSessionRequest -> diff --git a/acp/src/commonMain/kotlin/com/agentclientprotocol/agent/AgentSupport.kt b/acp/src/commonMain/kotlin/com/agentclientprotocol/agent/AgentSupport.kt index 1620587..0c99ce6 100644 --- a/acp/src/commonMain/kotlin/com/agentclientprotocol/agent/AgentSupport.kt +++ b/acp/src/commonMain/kotlin/com/agentclientprotocol/agent/AgentSupport.kt @@ -58,11 +58,12 @@ public interface AgentSupport { * Pagination is automatically handled by [com.agentclientprotocol.util.SequenceToPaginatedResponseAdapter]. * * @param cwd optional current working directory filter + * @param additionalDirectories optional additional directories filter * @param _meta optional metadata * @return a sequence of [SessionInfo] */ @UnstableApi - public suspend fun listSessions(cwd: String?, _meta: JsonElement?): Sequence { + public suspend fun listSessions(cwd: String?, additionalDirectories: List?, _meta: JsonElement?): Sequence { throw NotImplementedError("listSessions is not implemented. The capability is declared in AgentCapabilities.sessionCapabilities.list") } diff --git a/acp/src/commonMain/kotlin/com/agentclientprotocol/client/Client.kt b/acp/src/commonMain/kotlin/com/agentclientprotocol/client/Client.kt index b784470..ecab3d6 100644 --- a/acp/src/commonMain/kotlin/com/agentclientprotocol/client/Client.kt +++ b/acp/src/commonMain/kotlin/com/agentclientprotocol/client/Client.kt @@ -314,16 +314,18 @@ public class Client( * Sequences don't support suspending operations between value yields. * * @param cwd optional current working directory filter + * @param additionalDirectories optional additional directories filter * @param _meta optional metadata * @return a cold [Flow] of [SessionInfo] that lazily fetches pages as needed */ @UnstableApi public fun listSessions( cwd: String? = null, + additionalDirectories: List? = null, _meta: JsonElement? = null ): Flow { return PaginatedResponseToFlowAdapter.asFlow { cursor -> - AcpMethod.AgentMethods.SessionList(protocol, ListSessionsRequest(cwd, cursor, _meta)) + AcpMethod.AgentMethods.SessionList(protocol, ListSessionsRequest(cwd, additionalDirectories, cursor, _meta)) } } diff --git a/build.gradle.kts b/build.gradle.kts index 59374f0..ca8a50d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ plugins { private val buildNumber: String? = System.getenv("GITHUB_RUN_NUMBER") private val isReleasePublication = System.getenv("RELEASE_PUBLICATION")?.toBoolean() ?: false -private val baseVersion = "0.18.0" +private val baseVersion = "0.18.1" allprojects { group = "com.agentclientprotocol"