The use cases layer knows nothing about the views/presentation, and it provides functions and/or interfaces that are expressed entirely in terms appropriate for that layer, meaning, these do not assume anything about what kinds of views consume them - in principle, these should work equally well with a desktop GUI, a terminal, or a web interface, or IDK, some near-future AI that can reliably translate verbal commands into function calls. This is achievable, but in practice, because the presenter has to take the response from the use case and translate it to the GUI format, and vice versa, there's a cost involved, so your design is somewhat constrained by it in terms of how different the two representations arecan be.
In the "pull" variant, your presentation-layer code simply calls a method on a use case. In the "push" variant, you'd dependency-inject a presenter (which remember, is an implementation of an abstraction required by the use case) into the use case. (This is true even in a dynamic language where you don't actually have to inherit from a class/interface - there, the abstraction is the spec of this "output port" associated with the use case, even if it only exists in the documentation). This is fine because all the use case sees is the abstraction, which is "owned" by the use case, and in principle has no view-specific aspects to it (though in practice, sometimes that might not be entirely true due to the aforementioned cost, or simply because a choice of some framework forces you to pollute your use cases layer). Sometimes, the role of a dependency-injected presenter can be fulfilled by a simple lambda (the abstraction in that case is the required function signature).