Add Tools.aexecute_tool, which awaits async def tool callables and runs
blocking sync tools in a worker thread via asyncio.to_thread. The per-call
work (argument validation, policy evaluation, trace events, and tool-result
message building) is factored into shared helpers, so the sync execute_tool
and the new async path stay in lockstep with no duplicated tool-loop logic.