Ir al contenido principal
Stateful AI Agents: Why Your Automation Breaks

Stateful AI Agents: Why Your Automation Breaks

AI Integration
5 min readPor Daily Miranda Pardo

Your AI agent runs flawlessly in the demo. The client nods, everyone's impressed, the problem looks solved.

A week later you get the first alert: the agent sent three payment reminders to the same client on the same day. The client is furious. The team doesn't know what happened. And the agent is still running, blissfully unaware.

The problem is almost never the prompt. The problem is that your agent doesn't know where it is.

Stateless agents aren't agents — they're single-use scripts

When you build an automation agent — for invoicing, customer follow-up, report generation, whatever — the first trap is treating it like a regular program.

A regular program runs, finishes, and if you call it again, it starts from scratch. That's fine. Normal programs don't need to remember what they did last time because they operate on data that persists outside of them.

An AI agent in production needs to remember exactly where each process was left off and what it already executed. If it doesn't, you get bugs that sound impossible on paper:

  • Sending the same email twice after a process restart
  • Losing track of a customer conversation when the server reboots
  • Processing a payment that was already collected because state wasn't synced

This isn't an AI failure. It's an architecture failure.

Model your process as a state machine

A state machine defines explicitly what situations a process can be in, and what conditions allow transitions between them. No ambiguity. No way to skip steps.

Take invoice lifecycle as a concrete example:

DRAFT → SENT → REMINDED_1 → REMINDED_2 → PAID | OVERDUE

Each state represents a real, verifiable situation. Each transition has a condition: "move from SENT to REMINDED_1 only if 7 days have passed with no confirmed payment."

The LLM steps in where its intelligence actually adds value: drafting the reminder text, adapting tone to the client's history, deciding whether to escalate. The flow control — when to advance, when to wait, when to hand off to a human — is managed by the machine, not the model.

type InvoiceState =
  | 'DRAFT'
  | 'SENT'
  | 'REMINDED_1'
  | 'REMINDED_2'
  | 'PAID'
  | 'OVERDUE';

interface InvoiceProcess {
  invoiceId: string;
  state: InvoiceState;
  lastTransitionAt: Date;
  attempts: number;
}

async function advanceState(process: InvoiceProcess): Promise<InvoiceProcess> {
  const now = new Date();
  const days =
    (now.getTime() - process.lastTransitionAt.getTime()) / 86_400_000;

  if (process.state === 'SENT' && days >= 7) {
    const text = await generateReminder(process.invoiceId, 1);
    await sendEmail(process.invoiceId, text);
    return { ...process, state: 'REMINDED_1', lastTransitionAt: now, attempts: 1 };
  }

  if (process.state === 'REMINDED_1' && days >= 5) {
    const text = await generateReminder(process.invoiceId, 2);
    await sendEmail(process.invoiceId, text);
    return { ...process, state: 'REMINDED_2', lastTransitionAt: now, attempts: 2 };
  }

  if (process.state === 'REMINDED_2' && days >= 7) {
    return { ...process, state: 'OVERDUE', lastTransitionAt: now };
  }

  return process;
}

The key difference: state is read from and written to a database before and after every transition. The next scheduler run knows exactly where things stand, no assumptions.

State lives in the database, not in memory

The most common mistake in production agents is storing state in process memory. Works fine — until the server restarts, the process crashes, or a rolling deployment kicks in.

Three rules every stateful agent must follow:

1. Always read state before acting. Never assume. Query the database to know where the process stands.

2. Check idempotency before executing. Use an idempotency_key per action to detect if it already ran: reminder-{invoiceId}-REMINDED_1. If it exists in the logs, skip.

3. Save the new state in the same transaction as the action. If the email sends but the state write fails, the next run detects it and retries. With an atomic transaction, either both succeed or neither does.

async function processInvoice(invoiceId: string) {
  const process = await db.invoiceProcess.findUnique({ where: { invoiceId } });

  const key = `reminder-${invoiceId}-${process.state}`;
  const done = await db.emailLog.findUnique({ where: { idempotencyKey: key } });
  if (done) return;

  const text = await generateReminder(invoiceId, process.attempts + 1);
  await sendEmail(invoiceId, text);

  await db.$transaction([
    db.emailLog.create({ data: { idempotencyKey: key, sentAt: new Date() } }),
    db.invoiceProcess.update({
      where: { invoiceId },
      data: { state: 'REMINDED_1', lastTransitionAt: new Date(), attempts: 1 },
    }),
  ]);
}

This pattern eliminates duplicates. It doesn't matter if the process dies halfway through, if there's a network blip, or if the scheduler fires twice in quick succession — the agent checks before acting and only advances when it should.

The question to ask before deploying any agent

If you're evaluating whether to build or buy an AI automation — whether for business system integration, customer follow-up, or any workflow that touches money or reputation — there's one technical question that separates prototypes from production systems:

How does it persist state between runs? What happens if the process dies halfway?

A vague answer means the problems will show up later. And when they arrive in production, the cost isn't just technical: angry clients, inconsistent data, hours of debugging to figure out what happened and when.

For AI Driven Development projects and end-to-end automation, we implement this pattern from the design phase — not as an afterthought. It's part of what makes the agents we build survive past the first month in production.

If you want to audit an agent you already have, or start a new one on solid foundations:

Let's talk on WhatsApp →

Compartir artículo

LinkedInXWhatsApp

¿Procesos repetitivos en tu empresa?

Descarga gratis el Mapa de Automatización IA — los 5 procesos que más tiempo roban y cómo resolverlos.

Sin spam. Solo el PDF. Puedes darte de baja cuando quieras.

Escrito por Daily Miranda Pardo

Ayudo a empresas a automatizar procesos, crear agentes IA y conectar sistemas inteligentes.