You'd use asyncio.to_thread[0].
I also don't quite get your complaint... asyncio provides a high-level concurrency primitive with coroutines, and that's a good enough primitive for workflow engines. Even with asyncio you could spawn processes easily with aiomultiprocess[1], if you'd want or need to.
What's your use case for having more low-level concurrency primitives (thread/processes) available, having to deal with their synchronization, and running workflows sync?
[0]: https://docs.python.org/3/library/asyncio-task.html#asyncio....
No such thing has to be necessary. Tasks run fine on different threads/interpreters/processes. Message passing via queues is used to communicate which tasks need to run. Many asyncio users seem to wholly unaware of how well it works. Go-lang doesn't even have async.
Also, the claim made that something is better modeled as async is wholly unqualified.