AI Engineering2026-07-097 min read

Building a Resilient Support Bot with Vercel AI SDK v7 Durable Workflows

Process crashes used to mean lost context for AI agents. I tested the new WorkflowAgent in Vercel AI SDK v7 to see if it actually survives mid-thought restarts.

Varun Raj Manoharan
Varun Raj Manoharan
VercelAISDK v7AgentsTypeScript

Running multi-step agents in production usually feels like balancing plates. If your server restarts or a deployment goes out while an agent is thinking, you lose the entire state. The user has to start over, which is a terrible experience.

I wanted to see if the new WorkflowAgent in Vercel AI SDK v7 solves this. I built a simple customer support bot that performs a multi-step refund process: fetching user data, checking the policy, and issuing a refund via Stripe.

The Problem with Short-Lived Contexts

Usually, if an agent calls an external API and your Edge function times out, that execution is dead. Vercel's approach with v7 moves state management into a durable backend. You define the workflow, and the SDK checkpoints the state after every LLM generation and tool call.

Building the Durable Bot

The code looks surprisingly similar to the old chat wrapper, but you swap in the WorkflowAgent class and provide a persistence layer.

TypeScript
import { WorkflowAgent } from 'ai';
import { openai } from '@ai-sdk/openai';
import { postgresStore } from '@ai-sdk/postgres'; // The persistence layer

export const supportWorkflow = new WorkflowAgent({
  model: openai('gpt-4o'),
  store: postgresStore(process.env.DATABASE_URL),
  system: 'You are a support agent. You can fetch user details and issue refunds.',
  tools: {
    fetchUserDetails: {
      description: 'Get user purchase history',
      parameters: z.object({ userId: z.string() }),
      execute: async ({ userId }) => {
        // Fetch from DB
        return { purchases: [{ id: 'order_123', amount: 50, status: 'paid' }] };
      },
    },
    issueRefund: {
      description: 'Refund a specific order',
      parameters: z.object({ orderId: z.string() }),
      execute: async ({ orderId }) => {
        // Call Stripe
        return { status: 'refunded', amount: 50 };
      },
    },
  },
});

// To trigger or resume it:
export async function POST(req: Request) {
  const { workflowId, message } = await req.json();
  
  const result = await supportWorkflow.run({
    id: workflowId,
    prompt: message,
  });

  return Response.json(result);
}

Does it work?

I ran this locally, triggered a refund request, and then aggressively killed my Node process right after the agent called fetchUserDetails but before it called issueRefund.

When I restarted the server and pinged the same workflowId, the agent did not ask for the user details again. It loaded the checkpoint from Postgres, read the transaction history, and immediately called the Stripe tool to finish the job.

It works, but you have to be careful with your database choice. I started with a local Redis instance and had serialization issues with some of the more complex tool results. Sticking to Postgres or Vercel KV seems to be the intended path. If you are building agents that take more than five seconds to finish a task, you probably need to migrate to this.

Available for new projects

Let's build something great.

Have a project in mind? We are an elite software and AI development studio ready to bring your ideas to production. Let's talk about your roadmap.