Source m o = ConduitM () o m (); why is Source m o not ConduitM Void o m ()?
I can't think of a really good answer to this, but here's a mediocre answer: you can always "step" a ConduitM that is blocked on trivial input. So the promise of a Source is not that it never blocks, but rather, that it only blocks in such a way that it is trivial to unblock.
You may like the Producer type synonym better:
type Producer m o = forall i. ConduitM i o m ()
When you have a Producer m o, it can be instantiated to ConduitM Void o m (), because you can select i = Void.
Now for your main question...
So the thing about ConduitM composition is that the "upstream result" must be (). If you peel away the ConduitM layer of abstraction and take a look at Data.Conduit.Internal.Pipe, you'll find the operator you're looking for:
awaitE :: Pipe l i o u m (Either u i)
I'm not quite sure how to surface this into the ConduitM level of abstraction.