An agent plans several tool calls, some of which need others' results ("look up the user, then fetch their orders and their tickets"). Run everything that's ready in parallel, wave by wave.
calls maps each call id to the list of ids it depends on. Implement:
waves(calls): a list of waves, each a sorted list of ids whose dependencies all finished in earlier waves. Raise ValueError for an unknown dependency or a cycle.makespan(calls, durations): the total time if each call starts as soon as its dependencies finish (unlimited parallelism), which is the longest dependency chain by total duration