How do I communicate the value of the initialization vector to the end user? Should it be part of the encrypted message?
For CBC encryption, you would store the initialization vector as the beginning of

the ciphertext, regardless of whether you read in an IV or generated it yourself.

The CBC decryption algorithm would do what you described at the end of your post.

Your implementation should also offer access to the block cipher itself, without any mode of operation.