Мне удалось сделать это вот так
$posts = Post::leftJoin('threads', function($join) {
$join->on('posts.id', '=', 'threads.post_id');
})
->leftJoin('messages', function($join) {
$join->on('threads.id', '=', 'messages.thread_id')
->where('messages.id', '=', DB::raw('(select max(messages.id) from messages)'));
})
->orderByRaw('coalesce(messages.created_at, posts.created_at) DESC')
->get();