The runtime records whether each tool call executed, and the retry reads that record before acting. A call already recorded as executed is skipped and its result reused.
A timeout on its own cannot answer the question. A lost response looks identical whether the payment was sent or never reached the provider.
When a tool call times out, the caller knows the response did not arrive. The action behind it may have completed, may have failed, or may still be running. Retrying on that information sends the request a second time and hopes the far side deduplicates it.
Recording the outcome moves the question inside the system. The runtime gates the call, writes that it executed, and the retry reads that write. The decision no longer depends on inferring intent from silence.
Teams that hit this build idempotency keys, a deduplication table, and a reconciliation job that finds the duplicates the first two missed. Each piece is written to compensate for a missing record, and each is maintained forever.
Judopay rebuilt its mobile payment platform on Akka and cut production code by half, with the retry and reconciliation logic among the code that stopped being necessary.
The runtime record still prevents the second call from the agent side, which is where the retry originates. A key adds protection against duplicates created by the network.
A read that returns the same answer twice is safe to repeat. The record matters for calls that change something: a payment, a filing, a message, a write to a system of record.
The runtime marks it unresolved and the run escalates. Guessing is what the record exists to prevent. An unresolved payment is a decision for a person.
A database transaction covers the writes inside one system. The record covers a call to a system that shares no transaction with yours, which is why the runtime that made the call has to hold it.