AI Agent Compensation for Failed Tools
A saga-style ledger for agent side effects, with preconditions, idempotency, reverse-order compensation, ambiguous outcomes, approvals, and recovery evidence.
AI agent compensation begins when a tool call has already changed the world and a later step fails. Database transactions cannot atomically cover a SaaS reservation, a payment authorization, a calendar event, and an email, so recovery needs a durable ledger and domain-specific reverse actions.
The goal is not magical undo. It is a bounded workflow that knows which effects committed, which can be reversed, which require approval, and which ambiguous outcomes must stop automation for reconciliation.
- Forward effects and reverse recovery
- Construction logic
- Interpretive outcome
AI agent compensation begins before execution
At planning time, classify every proposed tool action as read-only, naturally idempotent, reversible, compensatable with loss, approval-required, or irreversible. Record the forward precondition, idempotency key, success evidence, compensation command, compensation precondition, expiry, authority, and escalation owner. If a high-impact step has no acceptable recovery, move it after all fallible preparation or require a human commit.
The AWS saga guidance describes coordinating distributed transactions as sequences of local transactions with compensations. Agent workflows add uncertainty in planning and tool selection, but they do not relax the transaction discipline. AI agent compensation should be compiled from approved tool contracts, never improvised from model prose after failure.
Use compensating tool actions that express business semantics: void an authorization, release a reservation, cancel an unpublished draft. A raw inverse such as “subtract five” may overwrite intervening work. Compensation returns the system to an acceptable business state, which can differ from the exact prior bytes. Name that acceptable state and any nonrecoverable effects, such as an email already seen.
Append intent before calling the tool
Persist a workflow generation, step identifier, tool identity, normalized arguments hash, principal, idempotency key, expected state transition, compensation descriptor, and status “intent recorded.” Only then call the provider. On success, append provider operation ID, response fingerprint, committed timestamp, and authoritative receipt. The ledger, not chat history, controls recovery.
Durable AI agent execution covers replay-safe state transitions. AI agent compensation adds a reverse transition for committed work. Both require that model generation happen outside deterministic workflow code or be captured as an immutable result. A replay must not ask the model for a new compensation plan and silently change the recovery path.
The ledger should be append-only with derived current state. Corrections become new events. Encrypt sensitive arguments and retain only the fields needed for reconciliation.
AI agent activity logs people can audit helps shape the user-facing explanation: show intended action, observed result, recovery action, and remaining effect without exposing credentials or irrelevant payloads. This is agent side-effect recovery as an inspectable system, not a conversational apology.
| Forward action | Recovery | Window | Automation |
|---|---|---|---|
| Reserve inventory | Release reservation | until fulfillment | automatic |
| Authorize card | Void authorization | provider window | automatic with receipt |
| Send email | No recall guarantee | none | disclose/escalate |
| Delete legal record | Policy-specific restore | varies | human approval |
Runnable artifact: The saga ledger executes only completed compensations, in reverse order, and separates a failed forward step from the committed prefix. Extend it with durable events and provider receipts before connecting real tools.
Save this worked fixture as agent-saga-ledger.test.mjs and run node agent-saga-ledger.test.mjs. Expected final line: PASS: 10 saga assertions.
import assert from "node:assert/strict";
async function runSaga(steps){const ledger=[];try{for(const step of steps){await step.do();ledger.push(step)}return {status:"done",ledger}}catch(error){for(const step of [...ledger].reverse())await step.undo();return {status:"compensated",ledger,error:error.message}}}
const events=[]; const step=(name,fail=false)=>({name,do:async()=>{events.push("do:"+name);if(fail)throw Error(name)},undo:async()=>events.push("undo:"+name)});
let n=0;const check=fn=>{fn();n++};
const failed=await runSaga([step("reserve"),step("charge"),step("email",true)]);
check(()=>assert.equal(failed.status,"compensated"));
check(()=>assert.deepEqual(events,["do:reserve","do:charge","do:email","undo:charge","undo:reserve"]));
check(()=>assert.equal(failed.ledger.length,2));
check(()=>assert.equal(failed.error,"email"));
events.length=0;const done=await runSaga([step("a"),step("b")]);
check(()=>assert.equal(done.status,"done"));check(()=>assert.equal(done.ledger.length,2));
check(()=>assert.deepEqual(events,["do:a","do:b"]));
check(()=>assert.equal(done.error,undefined));
const empty=await runSaga([]);
check(()=>assert.deepEqual(empty.ledger,[]));
check(()=>assert.equal(empty.status,"done"));
assert.equal(n,10);console.log("PASS: 10 saga assertions");
Treat timeout as unknown, not failed
A network timeout after submission does not prove the provider rejected the action. Retrying with a new key may duplicate it; compensating immediately may target an operation that has not become visible. Move the step to “outcome unknown,” query by idempotency key or operation ID, and reconcile against the provider's authoritative state before continuing either direction.
Idempotency keys need lifecycle contracts explains why a key includes request fingerprint, replay response, retention, and expiry. AI agent compensation should reuse the same operation identity for reconciliation and repeat the same compensation identity on retries. A provider that offers no lookup or idempotency support needs a stricter concurrency guard and often human review.
Define bounded retry schedules, not an infinite loop. Distinguish transient transport errors, rejected commands, committed operations, unknown outcomes, compensation conflicts, and expired reversal windows. Preserve raw provider status in restricted evidence while mapping it to a stable internal reason code.
Saga workflow agents stop when they cannot prove the next legal transition. Confidence from the language model has no authority over an ambiguous payment or reservation.
- 1Record uncertainty
Keep the original operation identity and stop dependent steps.
- 2Query authority
Look up by idempotency key, provider ID, and expected state fingerprint.
- 3Classify outcome
Choose not committed, committed, still pending, or conflicting evidence.
- 4Resume safely
Continue forward, compensate, or request a human decision with the complete receipt.
Order compensations by dependency, not chronology alone
Reverse completion order is a safe default when each step depends on its predecessor. Real workflows may form a graph: two independent reservations feed one shipment; a calendar event and draft invoice can compensate in parallel; payment release must wait until shipment cancellation is confirmed. Store explicit dependencies and compute a reverse topological schedule. Serialize operations that touch the same resource.
The Azure saga pattern distinguishes coordination approaches and the challenges of compensating transactions. For an agent, orchestration is usually easier to audit because one durable workflow owns the step ledger. Choreographed events can work, but each participant still needs correlation, deduplication, and an observable terminal state.
AI agent compensation should continue after one recovery failure only if policy declares independent remaining steps safe to attempt. Record partial recovery and escalate with the resources still changed. Never mark the workflow “rolled back” because the reverse loop ran; verify terminal business state.
A cancellation accepted asynchronously is not yet a released reservation. Background jobs need completion receipts provides the completion distinction.
Keep approvals valid through the reverse path
An approval to purchase does not automatically authorize a different compensating action with larger impact. Tool contracts should declare whether compensation inherits the forward approval, requires a new approval, or is always allowed as risk reduction. Bind approval to principal, workflow, action class, amount or scope, expiry, and argument fingerprint. Revalidate when the recovery plan changes.
For reversible agent execution, show the user what can actually be undone before commitment. “You can cancel until fulfillment begins” is useful; a generic undo icon is not. After failure, the interface should distinguish recovered effects, pending recovery, irreversible effects, and actions the user must take. Avoid asking them to decipher provider codes.
Security boundaries persist during compensation. Use short-lived workload identity with only the reverse capability needed for the current step. A compromised recovery worker should not gain broad forward authority.
Redact secrets from the ledger, sign or integrity-protect events, and ensure tenant context survives retries. A correct reverse sequence under the wrong account is a severe incident, not successful compensation.
Test failures at every seam
For each step, inject failure before dispatch, after dispatch but before receipt, after commit, during ledger append, during compensation, and after compensation but before acknowledgement. Repeat duplicate events, stale workflow generations, concurrent cancellation, expired approval, provider throttling, and partial outage. Assert external state and ledger state together. AI agent compensation passes only when they converge or the workflow enters a truthful reconciliation state.
Use fake provider adapters with stateful idempotency and operation lookup, then sandbox accounts for integration tests. Preserve a deterministic event trace and minimize real side effects. Recovery drills should include an irreversible communication so the interface and escalation process receive exercise, not just the happy reversible cases.
Measure time in unknown state, time to acceptable recovery, compensation success by tool, duplicate-prevention rate, manual intervention, expired windows, remaining economic effect, and user-visible disclosure latency. A low workflow error rate can hide catastrophic recovery gaps. Slice by provider, action, amount, tenant, and runtime revision. Publish only aggregated operational results unless you have verified permission to disclose specific incidents.
Publish the saga ledger as the completion proof
The final receipt lists workflow and policy versions, principal, approvals, every forward intent, idempotency key hash, provider operation ID, observation, committed state, compensation command, attempts, terminal verification, unresolved effects, and escalation owner. AI agent compensation is complete only when every committed step is retained intentionally, acceptably compensated, or explicitly handed to a human.
The Temporal guidance on compensating actions emphasizes registering compensations with care around failures. Pin runtime semantics and test replay because workflow engines differ in when code is durable. The model can propose a plan, explain a receipt, or select from approved tools; deterministic workflow code should enforce legal transitions and recovery ordering.
Review the receipt during tool onboarding. If the team cannot state how to identify commitment, look up ambiguity, reverse safely, verify terminal state, and communicate leftovers, the action is not ready for autonomous chaining. That constraint is creative rather than limiting: it encourages preparation before commitment, smaller effect scopes, and tools designed with recovery as a product capability instead of an emergency script.