diff --git a/acp-ktor-test/src/commonTest/kotlin/com/agentclientprotocol/ProtocolTest.kt b/acp-ktor-test/src/commonTest/kotlin/com/agentclientprotocol/ProtocolTest.kt index 9d72f6a..8298996 100644 --- a/acp-ktor-test/src/commonTest/kotlin/com/agentclientprotocol/ProtocolTest.kt +++ b/acp-ktor-test/src/commonTest/kotlin/com/agentclientprotocol/ProtocolTest.kt @@ -241,7 +241,7 @@ abstract class ProtocolTest(protocolDriver: ProtocolDriver) : ProtocolDriver by } catch (e: JsonRpcException) { assertEquals(errorMessage, e.message, "Error message should be propagated to client") - assertEquals(JsonRpcErrorCode.INTERNAL_ERROR, e.code, "Error code should be INTERNAL_ERROR") + assertEquals(JsonRpcErrorCode.INTERNAL_ERROR.code, e.code, "Error code should be INTERNAL_ERROR") } } @@ -290,7 +290,7 @@ abstract class ProtocolTest(protocolDriver: ProtocolDriver) : ProtocolDriver by fail("Expected JsonRpcException to be thrown") } catch (e: JsonRpcException) { - assertEquals(JsonRpcErrorCode.METHOD_NOT_FOUND, e.code, "Error code should be METHOD_NOT_FOUND") + assertEquals(JsonRpcErrorCode.METHOD_NOT_FOUND.code, e.code, "Error code should be METHOD_NOT_FOUND") } } } \ No newline at end of file diff --git a/acp-model/api/acp-model.api b/acp-model/api/acp-model.api index 0861988..29026f0 100644 --- a/acp-model/api/acp-model.api +++ b/acp-model/api/acp-model.api @@ -3101,14 +3101,20 @@ public final class com/agentclientprotocol/rpc/JsonRpcError$Companion { public final fun serializer ()Lkotlinx/serialization/KSerializer; } -public final class com/agentclientprotocol/rpc/JsonRpcErrorCode { - public static final field CANCELLED I - public static final field INSTANCE Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; - public static final field INTERNAL_ERROR I - public static final field INVALID_PARAMS I - public static final field INVALID_REQUEST I - public static final field METHOD_NOT_FOUND I - public static final field PARSE_ERROR I +public final class com/agentclientprotocol/rpc/JsonRpcErrorCode : java/lang/Enum { + public static final field AUTH_REQUIRED Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public static final field CANCELLED Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public static final field INTERNAL_ERROR Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public static final field INVALID_PARAMS Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public static final field INVALID_REQUEST Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public static final field METHOD_NOT_FOUND Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public static final field PARSE_ERROR Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public static final field RESOURCE_NOT_FOUND Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public final fun getCode ()I + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public final fun getMessage ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; + public static fun values ()[Lcom/agentclientprotocol/rpc/JsonRpcErrorCode; } public final class com/agentclientprotocol/rpc/JsonRpcKt { diff --git a/acp-model/src/commonMain/kotlin/com/agentclientprotocol/rpc/JsonRpc.kt b/acp-model/src/commonMain/kotlin/com/agentclientprotocol/rpc/JsonRpc.kt index cc7651f..fec6d94 100644 --- a/acp-model/src/commonMain/kotlin/com/agentclientprotocol/rpc/JsonRpc.kt +++ b/acp-model/src/commonMain/kotlin/com/agentclientprotocol/rpc/JsonRpc.kt @@ -76,14 +76,34 @@ public data class JsonRpcError( /** * Standard JSON-RPC error codes. */ -public object JsonRpcErrorCode { - public const val PARSE_ERROR: Int = -32700 - public const val INVALID_REQUEST: Int = -32600 - public const val METHOD_NOT_FOUND: Int = -32601 - public const val INVALID_PARAMS: Int = -32602 - public const val INTERNAL_ERROR: Int = -32603 - // The same code as in LSP - public const val CANCELLED: Int = -32800 +public enum class JsonRpcErrorCode(public val code: Int, public val message: String) { + /** Invalid JSON was received by the server. + * An error occurred on the server while parsing the JSON text. */ + PARSE_ERROR(-32700, "Parse error"), + + /** The JSON sent is not a valid Request object. */ + INVALID_REQUEST(-32600, "Invalid Request"), + + /** The method does not exist or is not available. */ + METHOD_NOT_FOUND(-32601, "Method not found"), + + /** Invalid method parameter(s). */ + INVALID_PARAMS(-32602, "Invalid params"), + + /** Internal JSON-RPC error. + * Reserved for implementation-defined server errors. */ + INTERNAL_ERROR(-32603, "Internal error"), + + /** The same code as in LSP */ + CANCELLED(-32800, "Request cancelled"), + + /** Authentication is required before this operation can be performed. + * This is an ACP-specific error code in the reserved range. */ + AUTH_REQUIRED(-32000, "Authentication required"), + + /** A given resource, such as a file, was not found. + * This is an ACP-specific error code in the reserved range. */ + RESOURCE_NOT_FOUND(-32002, "Resource not found") } @OptIn(ExperimentalSerializationApi::class) diff --git a/acp/src/commonMain/kotlin/com/agentclientprotocol/protocol/Protocol.kt b/acp/src/commonMain/kotlin/com/agentclientprotocol/protocol/Protocol.kt index b8be121..4f72566 100644 --- a/acp/src/commonMain/kotlin/com/agentclientprotocol/protocol/Protocol.kt +++ b/acp/src/commonMain/kotlin/com/agentclientprotocol/protocol/Protocol.kt @@ -44,7 +44,7 @@ public class AcpExpectedError(override val message: String) : Exception(message) public fun acpFail(message: String): Nothing = throw AcpExpectedError(message) public fun jsonRpcMethodNotFound(message: String): Nothing = - throw JsonRpcException(JsonRpcErrorCode.METHOD_NOT_FOUND, message) + throw JsonRpcException(JsonRpcErrorCode.METHOD_NOT_FOUND.code, message) /** * Exception thrown for JSON-RPC protocol errors. @@ -380,17 +380,17 @@ public class Protocol( logger.trace(e) { "Expected error on '${request.method}'" } sendResponse( request.id, null, JsonRpcError( - code = JsonRpcErrorCode.INVALID_PARAMS, message = e.message ?: "Invalid params" + code = JsonRpcErrorCode.INVALID_PARAMS.code, message = e.message ) ) } catch (e: JsonRpcException) { logger.trace(e) { "JsonRpcException on '${request.method}'" } - sendResponse(request.id, null, JsonRpcError(code = e.code, message = e.message ?: "Internal error", data = e.data)) + sendResponse(request.id, null, JsonRpcError(code = e.code, message = e.message, data = e.data)) } catch (e: SerializationException) { logger.trace(e) { "Serialization error on ${request.method}" } sendResponse( request.id, null, JsonRpcError( - code = JsonRpcErrorCode.PARSE_ERROR, message = e.message ?: "Serialization error" + code = JsonRpcErrorCode.PARSE_ERROR.code, message = e.message ?: "Serialization error" ) ) } catch (ce: CancellationException) { @@ -399,7 +399,7 @@ public class Protocol( sendResponse( request.id, null, JsonRpcError( - code = JsonRpcErrorCode.CANCELLED, + code = JsonRpcErrorCode.CANCELLED.code, message = ce.message ?: "Cancelled" ) ) @@ -408,13 +408,13 @@ public class Protocol( logger.error(e) { "Exception on ${request.method}" } sendResponse( request.id, null, JsonRpcError( - code = JsonRpcErrorCode.INTERNAL_ERROR, message = e.message ?: "Internal error" + code = JsonRpcErrorCode.INTERNAL_ERROR.code, message = e.message ?: "Internal error" ) ) } } else { val error = JsonRpcError( - code = JsonRpcErrorCode.METHOD_NOT_FOUND, message = "Method not supported: ${request.method}" + code = JsonRpcErrorCode.METHOD_NOT_FOUND.code, message = "Method not supported: ${request.method}" ) sendResponse(request.id, null, error) } @@ -483,17 +483,17 @@ public class Protocol( private fun convertJsonRpcExceptionIfPossible(jsonRpcException: JsonRpcException): Exception { when (jsonRpcException.code) { - JsonRpcErrorCode.PARSE_ERROR -> { + JsonRpcErrorCode.PARSE_ERROR.code -> { return SerializationException(jsonRpcException.message, jsonRpcException) } - JsonRpcErrorCode.INVALID_PARAMS -> { - return AcpExpectedError(jsonRpcException.message ?: "Invalid params") + JsonRpcErrorCode.INVALID_PARAMS.code -> { + return AcpExpectedError(jsonRpcException.message) } - JsonRpcErrorCode.CANCELLED -> { + JsonRpcErrorCode.CANCELLED.code -> { return CancellationException( - jsonRpcException.message ?: "Cancelled on the counterpart side", + jsonRpcException.message, jsonRpcException ) }