What you described — (request_id, tool, input_hash, response) with a unique constraint — is basically the same core idea: treat the tool execution as a durable receipt and return the stored result on retries.
While experimenting with agents I kept seeing retries coming from multiple layers (agent loops, HTTP retries, queue workers), so the goal was to wrap that execution guard into a small library instead of re-implementing the pattern each time.
The tricky part you mentioned about error states is exactly what I ran into as well. If the execution fails you don’t want to record it in a way that blocks legitimate retries but also don’t want to silently replay a failure as if it succeeded.
Curious how you ended up modeling that in Postgres — did you separate failure states from successful receipts or just include a status flag in the same row?