
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.
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.
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.
Related reading
Our monthly client reports followed a 40-line prompt nobody dared touch. I moved the whole playbook into an uploaded skill using the new uploadSkill API in Vercel AI SDK v7.
One-shot code execution can't build software. An autonomous coding agent needs a filesystem that survives across turns — to install dependencies, edit files, run the test suite, read the failures, and open a pull request. This builds that with a persistent E2B sandbox.
Voice agents used to mean marrying one provider's WebSocket event format. I used the new experimental realtime API in Vercel AI SDK v7 to build an order-status voice agent I can move between providers.
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.