in a2a/a2a-transport/a2a-transport-core-jsonrpc/src/commonMain/kotlin/ai/koog/a2a/transport/jsonrpc/JSONRPCServerTransport.kt [50:103]
protected fun parseJSONRPCRequest(raw: String): Pair<JSONRPCRequest, A2AMethod> {
val jsonBody = try {
JSONRPCJson.decodeFromString<JsonObject>(raw)
} catch (e: SerializationException) {
throw A2AParseException("Cannot parse request body to JSON:\n${e.message}")
}
// According to A2A TCK, need to parse id early to reply with provided id in error messages
val id = jsonBody["id"]?.let {
try {
JSONRPCJson.decodeFromJsonElement<RequestId>(it)
} catch (e: SerializationException) {
throw A2AInvalidRequestException("Cannot parse request id to JSON-RPC id:\n${e.message}")
}
}
val a2aMethod = (jsonBody["method"] as? JsonPrimitive)
?.content
?.let {
A2AMethod.entries.find { m -> m.value == it }
?: throw A2AMethodNotFoundException("Method not found: $it", id)
}
?: throw A2AInvalidRequestException("No method parameter", id)
val params = jsonBody["params"]
?.let {
try {
JSONRPCJson
.decodeFromJsonElement<JsonObject>(it)
.also {
// According to A2A TCK, empty parameter names are not allowed
if (it.keys.any { it.isEmpty() }) {
throw A2AInvalidParamsException("Empty parameter names are not allowed", id)
}
}
} catch (e: SerializationException) {
throw A2AInvalidParamsException("Cannot parse request params to JSON:\n${e.message}", id)
}
}
val jsonrpc = jsonBody["jsonrpc"]
?.jsonPrimitive?.content
?.takeIf { it == JSONRPC_VERSION }
?: throw A2AInvalidRequestException("Unsupported JSON-RPC version", id)
val jsonrpcBody = JSONRPCRequest(
id = id ?: throw A2AInvalidRequestException("No id parameter"),
method = a2aMethod.value,
params = params ?: JsonNull,
jsonrpc = jsonrpc,
)
return jsonrpcBody to a2aMethod
}