Building durable agents with Temporal and AI SDK by Vercel

AUTHORS
Melissa Herrera
DATE
Jan 20, 2026
CATEGORY
DURATION
9 MIN

If you’re a TypeScript developer building AI applications, chances are you’ve come across the AI SDK by Vercel. And if you haven’t, you’re in for a treat! It does exactly what a good SDK should: makes it easy to get started, is actively maintained, and handles the hard stuff.

Now, imagine taking those same agents you’re already building and adding durability guarantees — the ability to run for hours, survive infrastructure hiccups, and pick up exactly where they left off.

I’ve been working with the new Temporal integration for the AI SDK, and I’m excited to share how it solves these problems. The integration brings Durable Execution to your AI agents built with the AI SDK by Vercel.

What does that mean? For workflows that need to run reliably over extended periods, your AI agents gain the ability to handle challenges like hitting rate limits when calling LLMs or experiencing network hiccups mid-request. Temporal manages retries, state, and recovery, picking up exactly where your application left off. No repeated API calls, no wasted tokens, no lost progress.

And the best part? You get all of this without adding complexity to your code. If you’re new to Temporal, one of our core principles is that the developer codes the happy path, and Temporal handles the errors for you. The AI SDK shares this philosophy, which is what makes this integration work so well.

In this post, I’ll walk you through how the integration works, what you can build with it, and why it matters. I’ll start with a quick overview of the AI SDK, then cover the Temporal integration, and finally walk through a real-world example that shows you what is possible when you combine these tools.

Let’s go!

The AI SDK by Vercel#

The AI SDK makes working with language models in TypeScript straightforward. Import generateText, pass in a model and a prompt, and you’re talking to an LLM:

import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';

async function haikuAgent(prompt: string): Promise<string> {
  const result = await generateText({
    model: openai('gpt-4o-mini'),
    prompt,
    system: 'You only respond in haikus.',
  });
  return result.text;
}

Want to give your agent tools? Just add the tools parameter with a description, schema, and execute function:

import { generateText, tool } from 'ai';
import { z } from 'zod';

async function toolsAgent(question: string): Promise<string> {
  const result = await generateText({
    model: openai('gpt-4o-mini'),
    prompt: question,
    system: 'You are a helpful agent.',
    tools: {
      getWeather: tool({
        description: 'Get the weather for a given city',
        inputSchema: z.object({
          location: z.string().describe('The location to get the weather for'),
        }),
        execute: async ({ location }) => fetchWeather(location),
      }),
    },
  });
  return result.text;
}

And just like that, you now have a tool-calling agent with a built-in agentic loop. When the model decides it needs to use a tool, the SDK executes it, feeds the result back to the model, and continues — repeating this cycle until the model has everything it needs to respond to the user’s query. Clean and intuitive.

The AI SDK handles the agentic loop beautifully. Now, with Temporal, you can extend that same developer experience to long-running workflows that need durability guarantees: think multi-step agents, overnight batch processing, or any workflow where you want guaranteed completion regardless of what happens to your infrastructure.

Adding Temporal: The plugin approach#

Enter: Temporal!

The Temporal integration uses a plugin architecture that keeps your AI SDK code familiar while adding durability behind the scenes.

First, you configure your Temporal Worker with the AiSDKPlugin:

import { openai } from '@ai-sdk/openai';
import { AiSDKPlugin } from '@temporalio/ai-sdk';
import { Worker } from '@temporalio/worker';

const worker = await Worker.create({
  plugins: [
    new AiSDKPlugin({
      modelProvider: openai,
    }),
  ],
  connection,
  namespace: 'default',
  taskQueue: 'ai-sdk',
  workflowsPath: require.resolve('./workflows'),
  activities,
});

The modelProvider tells the plugin which AI provider to use. You can swap in OpenAI, Anthropic, Google, or any other provider the AI SDK supports.

In your Workflow code, instead of importing from @ai-sdk/openai directly, use temporalProvider.languageModel():

import { generateText } from 'ai';
import { temporalProvider } from '@temporalio/ai-sdk';

export async function haikuAgent(prompt: string): Promise<string> {
  const result = await generateText({
    model: temporalProvider.languageModel('gpt-4o-mini'),
    prompt,
    system: 'You only respond in haikus.',
  });
  return result.text;
}

That’s the key change: temporalProvider.languageModel(‘gpt-4o-mini’) instead of openai(‘gpt-4o-mini’).

When you call generateText() with this provider, the plugin automatically wraps the LLM call in a Temporal Activity. Temporal tracks when it started, what arguments it received, whether it completed, and what it returned. If something fails (rate limit, network issue, process crash), Temporal handles the retry or recovery.

Two lines change. Full durability added.

Tools in Workflow context#

When you provide tools to your agent in a Temporal Workflow, those tool functions run in the Workflow context and need to follow Workflow rules. Specifically, non-deterministic operations like API calls must run as Activities.

So if your tool needs to call an external API, implement that as an Activity:

// activities.ts
export async function getWeather(input: {
  location: string;
}): Promise<{ city: string; temperatureRange: string; conditions: string }> {
  // Call your weather API here
  return {
    city: input.location,
    temperatureRange: '14-20C',
    conditions: 'Sunny with wind.',
  };
}

Then proxy that Activity in your Workflow and pass it to the tool’s execute function:

import { proxyActivities } from '@temporalio/workflow';
import { generateText, tool } from 'ai';
import { temporalProvider } from '@temporalio/ai-sdk';
import { z } from 'zod';
import type * as activities from './activities';

const { getWeather } = proxyActivities<typeof activities>({
  startToCloseTimeout: '1 minute',
});

export async function toolsAgent(question: string): Promise<string> {
  const result = await generateText({
    model: temporalProvider.languageModel('gpt-4o-mini'),
    prompt: question,
    system: 'You are a helpful agent.',
    tools: {
      getWeather: tool({
        description: 'Get the weather for a given city',
        inputSchema: z.object({
          location: z.string().describe('The location to get the weather for'),
        }),
        execute: getWeather,
      }),
    },
  });
  return result.text;
}

Now your tool calls are durable too. If the weather API is down, Temporal retries. If your Worker crashes after the LLM decides to use the tool but before the tool executes, Temporal picks up right where it left off. In the Temporal UI screenshot below, you can see an Activity that failed, retried three times, recovered, and continued all the way to the “Completed” state.

Screenshot 2026-01-15 at 2.21.32 PM

But wait — isn’t an LLM call also non-deterministic? Shouldn’t we wrap those in Activities too?

You’re right to think that! This is where the plugin does the heavy lifting. When you use temporalProvider.languageModel(), the plugin automatically wraps every LLM call in a Temporal Activity behind the scenes. You don’t have to think about it. The generateText() call in your Workflow looks like regular AI SDK code, but Temporal handles persistence and retries under the hood.

So in the example above, you get durability in two places: the tool execution runs as an Activity you defined explicitly, and the LLM calls run as Activities the plugin creates implicitly. If the model call fails due to a rate limit, Temporal retries it. The whole agentic loop becomes durable without you having to write each piece manually.

Real-world example: A daily news briefing agent#

Let me show you the kind of use case where Temporal really shines: a long-running, multi-phase workflow where durability is imperative. I built a daily news briefing agent that researches topics, summarizes findings from each, and generates a personalized report.

This agent works in three phases:

  1. Search: Query the web for recent news on multiple topics, running searches in parallel
  2. Summarize: Use LLM calls to extract key points from each topic’s results
  3. Generate: Combine everything into a final briefing

Starting point: The AI SDK#

Here’s the daily briefing agent built with the AI SDK. It kicks off agents in parallel to search for multiple topics, summarizes the findings, and generates a final report:

import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';

export async function generateDailyBriefing(topics: string[]): Promise<DailyBriefing> {
    // PHASE 1: Search all topics (in parallel)
    const searchResults = await Promise.all(
      topics.map(topic => searchTopic(topic))
    );

    // PHASE 2: Summarize all findings (in parallel)
    const summaries = await Promise.all(
      searchResults.map(result => summarizeTopic(result))
    );

    // PHASE 3: Generate final briefing
    const briefingText = await generateBriefing(summaries);

    return {
      date: new Date().toISOString().split('T')[0],
      topics: summaries,
      briefingText,
      totalSources: searchResults.reduce((acc, r) => acc + (r.sources?.length || 0), 0),
    }; 
  } 

Adding durability with Temporal#

Now let’s add Temporal to make this workflow fully durable. The code stays almost identical; we’re just unlocking new capabilities here:

// activities.ts
export async function searchTopic(topic: string): Promise<SearchResult[]> {
  return searchWeb(topic);
}
// workflows.ts
import { proxyActivities } from '@temporalio/workflow';
import { generateText } from 'ai';
import { temporalProvider } from '@temporalio/ai-sdk';
import type * as activities from './activities';

const { searchTopic } = proxyActivities<typeof activities>({
  startToCloseTimeout: '2 minutes',
  retry: { maximumAttempts: 3 },
});

export async function dailyBriefingWorkflow(topics: string[]): Promise<string> {
  // Phase 1: Search (as Activities)
  const searchResults = await Promise.all(
    topics.map(topic => searchTopic(topic))
  );

  // Phase 2: Summarize (durable LLM calls)
  const summaries = await Promise.all(
    searchResults.map(results =>
      generateText({
        model: temporalProvider.languageModel('gpt-4o-mini'),
        prompt: `Summarize: ${JSON.stringify(results)}`,
      })
    )
  );

  // Phase 3: Generate briefing (durable LLM call)
  const briefing = await generateText({
    model: temporalProvider.languageModel('gpt-4o-mini'),
    prompt: `Create a news briefing from: ${summaries.map(s => s.text).join('\n')}`,
  });

  return briefing.text;
}

The web searches run as Activities with automatic retries. The LLM calls use temporalProvider so their results are persisted.

Screenshot 2026-01-15 at 2.24.15 PM

In the Temporal UI, we get full visibility into each phase. We can monitor its progress, pinpoint exactly where a failure might have occurred, and track inputs and outputs between tasks.

What this gives you#

With the Temporal integration for the AI SDK by Vercel, you get:

  • Automatic retries for transient failures like rate limits and network issues
  • State persistence so you don’t lose any progress after a crash
  • Full visibility into every step via the Temporal UI
  • Cost efficiency because completed work is never repeated
  • The same AI SDK API TypeScript developers know and love

Your developer experience stays familiar, and your long-running agents gain the durability guarantees they need.

Get started#

Ready to add durability to your long-running AI agents?

If you have questions or want to share what you’re working on, come find us in the Temporal Community Slack in #topic-ai.

Happy building!

Temporal Cloud

Ready to see for yourself?

Sign up for Temporal Cloud today and get $1,000 in free credits.

Build invincible applications

It sounds like magic, we promise it's not.