All posts

An AI agent failed halfway through a task: how to resume without doing it twice

What happens when 1C has created an invoice but its response is lost: how checkpoints, heartbeats, idempotency keys, and an audit log help an agent resume after failure, avoid a duplicate write, and stop when the outcome cannot be proved.

SA

Samreshuuu

September 4, 2026 · 13 min read

Contents

In short. The most dangerous AI agent failure is not an action that clearly failed. It is an action that may have succeeded while its confirmation was lost. The invoice may already exist in 1C, the email may have reached the customer, or the price may have changed in the seller account, while the agent sees only a timeout. A blind retry turns recovery into a duplicate. A reliable agent therefore needs four separate abilities: remember its place in the task, detect a stopped process, avoid performing the same write twice, and stop honestly when the outcome cannot be proved. Here is how those abilities work in Samreshuuu, and why a Retry button fixes none of them on its own.

You asked an agent to issue an invoice to a customer. 1C accepted the request, created the document, and began sending a response. At that moment, the connection disappeared.

As far as 1C is concerned, the job is complete: the invoice exists. As far as the agent is concerned, it is not: no response arrived. Repeating the command may create a second invoice. Not repeating it may leave the task unfinished. Merely telling the user that there was an error may send someone off to create the invoice manually, with the same risk of duplication.

This is not a rare edge failure. It is an ordinary state of any work performed over a network. The request and the response travel separately, and losing the response says nothing about the fate of the request.

A chat can end with “please try again.” A coworker that owns a piece of work cannot. It first has to answer a different question: what has already happened?

A failure has three outcomes, not two

Most interfaces draw two states: success and failure. That is not enough for an action that changes something.

What the agent seesWhat may have happened in the systemIs a retry safe?
The service rejected the request before executionNothing changedYes, if the cause is temporary
The service confirmed successThe change happenedNo retry is needed
The response was lostThe change may or may not have happenedOnly after obtaining evidence

The third state is the expensive one. Everyday interfaces have no good name for it, so they often hide it behind the word “error.” But a connection failure and an operation rejection are different events. A timeout says only that the response did not arrive in time. It does not say whether the server managed to take a payment, create an order, or send an email.

In distributed systems, this is an operation with an unknown fate. In business language, the rule is simpler: do not do it again until you have checked the first attempt.

Why an ordinary retry is dangerous here

Retries work well for reads. If the order list did not load, request it again. If a report did not open, wait and read it again. The outside state does not change.

Writes are different:

  • creating an invoice again produces two documents;
  • sending an email again gives the customer two identical demands;
  • submitting a payment again may charge the account twice;
  • changing a price again may apply the same adjustment a second time;
  • clicking Submit again in a browser may send an already completed form twice.

AWS frames the problem in much the same way: retries are useful only while several transmissions of one request still lead to one result. Stripe therefore accepts an idempotency key on creation requests. A retry carrying the same key returns the result of the first operation instead of creating a second one.

But the key solves only one part of the problem. The agent must still remember which assignment it was doing, how far it had progressed, and why it decided to repeat this particular call. Reliability is therefore assembled from four layers, not enabled by one setting.

Layer one: the task remembers where it stopped

If the entire course of work exists only in a process's memory, losing the process also erases the work. A new worker receives the original assignment and starts from the beginning: it reads the documents again, builds the table again, and eventually reaches the same write again.

A long-running task in Samreshuuu stores checkpoints. After a working step, the agent state, its findings, created files, and current iteration are persisted. Execution and state live separately: the process can be lost without losing the work it has already completed.

This is not merely a saved answer. It is a bookmark in a case file. It records not only the page where work stopped, but also which sources have been read, which tools have been called, and what they returned.

Temporal describes the same idea as durable execution: a stream of work survives the loss of its worker and is restored in another process from persisted state. The important part is not a particular technology. It is the separation of two things that an ordinary chat joins together: the task lives longer than the process executing it right now.

Layer two: something must notice the stop

A checkpoint is useless if nobody notices that the work stopped.

Every running task has a heartbeat, a small signal that says “I am still working.” A separate process watches that signal and the current execution owner rather than trusting a reassuring label in the interface. If a worker disappears or stops responding, the execution returns to the queue and continues from its latest checkpoint.

There is another unpleasant race here. The old worker may not be entirely dead. It can wake up after another worker has already continued its task. Two processes now believe they own the same execution.

That is why every new run receives an attempt number. A result is accepted only from the current attempt. The late process may finish its computation, but it cannot overwrite the result of the worker that has already taken over. This does not make the model smarter. It stops two equally smart models from controlling the same row at the same time.

Layer three: a repeated call must not become a repeated action

A checkpoint answers “where were we?” Idempotency answers a different question: “have we already done exactly this?”

Before a mutating call, Samreshuuu constructs its signature from the task phase, tool name, and arguments. One durable slot exists for an identical action within the same phase.

There are three possible outcomes:

  1. The call is new: the agent claims the slot and executes it.
  2. The call has already completed: the agent receives the stored result and does not execute it again.
  3. The call is still running: a second executor is not allowed to enter concurrently.

This protects against more than network retries. A model can produce the same call again after its context has been restored. The outside system does not care why: two identical calls would still be two actions.

Local protection cannot, however, rewrite the rules of somebody else's API. If the external service accepted a request and our process disappeared before storing the result, an internal slot alone is not enough. The other half of the contract has to come from the service: an idempotency key, or a way to find the created object unambiguously by a business key.

A request with an unknown fate may therefore be repeated only when safety can be proved:

  • the method does not change state;
  • the external API accepts an idempotency key;
  • or a separate read can first confirm that the action has not happened.

At the transport layer, Samreshuuu automatically repeats a lost request only in the first two cases. In the third case, repetition is a new agent decision made after reading the system. Without evidence, the agent does not guess: it leaves the outcome unknown and asks a person.

Layer four: the audit log records what happened, not what the agent thought

A chat transcript is poor investigation material. It mixes reasoning, intermediate data, service responses, and the explanation given to the user. It is hard to prove from that mixture whether a particular write took place.

A mutating action therefore receives a separate audit entry. It records:

  • which tool was called;
  • which area and connected account the action concerned;
  • whether human approval was required;
  • how the call ended;
  • which execution and tool call performed it;
  • whether a reverse action can be constructed.

This is not a screen recording of the agent or a feed of its private reasoning. The log answers a narrower question: which changes did the agent leave behind?

Braintrust describes observability as an active loop: find recurring failures in production traces, understand their cause, turn the cases into evaluations, and measure the next version. For a business owner, the bottom layer of that loop is simpler. If a coworker changed something, there must be a record from which the result, decision, and reason can be recovered.

Consider that invoice in 1C

Suppose the task says: “Every weekday, find shipments without an invoice, prepare the invoices in 1C, and show them to me before emailing customers.”

A normal run looks like this:

  1. The agent reads shipments and existing invoices.
  2. It saves the identified shipment, customer, and amount combinations.
  3. Before creating a document, it records a specific intent.
  4. It creates the invoice.
  5. It reads the new document back and saves its identifier.
  6. It requests approval before emailing the customer.

Now the network disappears during step four.

A poor agent sees a timeout and calls Create invoice again.

A reliable agent distinguishes two situations. If the connector returned an explicit rejection before execution, the request can follow the ordinary retry ladder. If the response was lost after the request had been transmitted, its fate is unknown. The agent first reads invoices for the same customer, contract, amount, and period. If it finds exactly one matching document, it continues from there. If it finds none, it creates one. If it finds two, or cannot prove the relationship, it stops and presents the evidence to a person.

The next boundary is even stricter. A sent email cannot be “sent back,” so the absence of a confirmation after sending is not a reason to send it again. The agent first checks the Sent folder or the provider's delivery status. If neither can be checked, the correct result is not “sending failed.” It is “I could not prove whether the email was sent, so I did not send it again.”

That answer sounds less confident. It also avoids turning technical uncertainty into two emails to the customer.

Why the browser is a separate case

An API request can carry an identifier. A click cannot.

Two calls to Press Enter may be an accidental repeat, or they may submit two different forms. The same coordinates and keys prove nothing about the result. Samreshuuu therefore does not apply the same deduplication to browser gestures that it applies to connector calls.

If a browser operation is interrupted, the agent receives an honest instruction: the action may have run, so inspect the current page state first. After clicking Pay, it looks for confirmation and a new order status instead of clicking again merely because it missed the success animation.

This is an important boundary for every agent with a computer. Giving it a browser of its own and the ability to resume after a failure does not make every action repeatable. Sometimes recovery is not repeating the step. It is observing again.

“Exactly once” is not a property of the whole task

The phrase exactly once sounds like a promise that an agent will never duplicate anything. That is not an honest promise for distributed work.

You can allow only one process into a local section. You can store the result of a call. You can give an external service a key and receive its promise not to create a second object. You can read the state after an uncertain response. But if the outside system accepts no key, exposes no operation history, and has no unique business identifier, uniqueness cannot be proved from outside.

A reliable system therefore makes three narrower promises:

  • repeat where repetition is safe;
  • verify where the result can be read;
  • stop where the outcome cannot be proved.

The last item is not an agent weakness. It is a boundary of authority that a human coworker should also observe.

What to ask an AI agent vendor

Demos almost always run without failures. Reliability is therefore better tested with five questions than with a demonstration.

What happens if a worker disappears ten minutes into a task? “The task starts again” is worse than “it continues from its saved step.”

How does the system distinguish a temporary rejection from a lost response? If both are called a retryable error, mutating requests will eventually be duplicated.

Where is the result of an already completed action stored? The message history is not enough. There must be an address for the particular call and its result.

What happens when two executors believe they own one task? A queue alone does not protect against a worker that wakes up after its work has been handed to another.

What does the user see when the result cannot be proved? A good answer contains the state, the last confirmed action, and a safe next step. “Something went wrong, try again” is not an answer for a system allowed to write.

Reliability begins after the first failure

While an agent only reads data and writes advice in a chat, it can be judged by answer quality. The moment it receives a schedule and permission to change working systems, it acquires a second criterion: how it handles unfinished work.

A reliable agent still fails. Networks still flicker, services return 500 errors, processes restart, and browsers close between the click and its confirmation. The difference appears afterwards:

  • it remembers where it stopped;
  • a new executor does not fight the old one for the same task;
  • a completed action is not executed again;
  • an unknown outcome is not renamed as a failure;
  • a person is asked only when the system runs out of evidence.

This is where a chat becomes a coworker: not when it learns to press a button, but when it learns not to press it a second time without a reason.


Last updated: September 4, 2026.

Sources: n8n — How To Build Reliable Workflows With API Idempotency; Temporal — The thread is the Workflow: Durable AI agents without changing Agent code; Braintrust — One connected system for agent observability; AWS Builders' Library — Making retries safe with idempotent APIs; Stripe — Idempotent requests.

Put it into practice

Connect your services and hand this task to an AI agent: no manual routine, no spreadsheets.