I am using sodiumoxide, a Rust binding to libsodium that provides a function named sealedbox that requires the receiver's public key. However, they also mention that the message is encrypted with an ephemeral public key.
Does that mean that the sealedbox provides forward secrecy, or do I need to implement forward secrecy myself?
Basically, you have forward secrecy if all the used key pairs are ephemeral and that the private keys (NaCl calls these "secret keys") are destroyed dutifully after (one-time) usage. In the case of NaCl, both the sender and receiver use a key pair (as this is basically key agreement / ECIES). The key pair of the receiver is usually static, while the sender's key pair is ephemeral.
If you use one static public key of the receiver, you do not have forward security because the receiver could leak the private key. Unfortunately, this is the standard mode of operation for most encryption routines, including NaCl / libsodium.
The trick is, of course, to establish trust in the receiver's public key beforehand - otherwise, you may be using the key of an adversary instead. If you want to have forward security, then you could share and sign a new public key after each usage and preferably keep the secret key pair alive for as short a time as possible. However, now you are closer to developing transport security than application-level message encryption.