Vercel AI agents: the AI SDK, Eve, and when to use each
Vercel ships two ways to build an AI agent — the AI SDK's loop inside your app, and Eve's durable deployed agents. What each one is for, and how they combine.
Vercel has two agent stories, and the names don't say which is which
Search for how to build an AI agent on Vercel and you land on two different products. The AI SDK is a TypeScript library — npm install ai — that runs a model-and-tools loop inside code you already have. Eve is a framework and runtime for agents that exist as deployed services of their own, with schedules, channels and sessions that survive for days.
Neither replaces the other, and the confusion is understandable: both are Vercel's, both say "agent," and both give a model tools to call. The difference that actually decides between them is lifecycle. An AI SDK agent lives inside one of your requests and ends when the response does. An Eve agent is the application — it has an address, a memory, and reasons to wake up that have nothing to do with a user clicking something.
Get that distinction right and the choice mostly makes itself. This post walks through what each looks like, where the boundary runs, and the cases where you want both at once.
The AI SDK: an agent loop inside your app
The AI SDK is Vercel's general toolkit for calling language models from TypeScript — provider-agnostic, so the same code runs against OpenAI, Anthropic, Google or Vercel's AI Gateway. Its agent story is the loop it runs when you hand generateText some tools and permission to keep going:
import { generateText, tool, stepCountIs } from "ai"
import { z } from "zod"
const lookupOrder = tool({
description: "Look up one order by its id and return its status.",
inputSchema: z.object({
orderId: z.string().describe("The id, as printed on the confirmation email."),
}),
execute: async ({ orderId }) => orders.get(orderId),
})
const result = await generateText({
model: "openai/gpt-5",
system: "You answer questions about orders…",
tools: { lookupOrder },
stopWhen: stepCountIs(10),
prompt: "Where is order 10432?",
})
The model decides to call lookupOrder, the SDK executes it, feeds the result back, and the model goes around again until it has an answer or hits the step cap. That is the same model-tools-loop machine every agent is — delivered as a function call in your route handler, server action, or script.
Everything about this shape is request-scoped. State is the conversation you pass in. The loop's budget is stopWhen. When the response streams back to the browser — the SDK's useChat hook exists for exactly that — the agent is gone. Nothing was deployed, scheduled, or left running.
That is a feature, not a limitation. A chat box in your product, an extraction step in a pipeline, a copilot that answers over your data — these are app features that happen to use a model, and a library that stays inside your existing code and deploy story is the right amount of machinery for them.
Eve: the agent as a deployed service
Eve inverts the relationship. Instead of an agent living inside your app, the agent is the deployable unit — a folder that Eve's runtime turns into a durable backend service:
my-agent/
agent/
instructions.md ← the system prompt
tools/ ← one file per tool
skills/ ← playbooks loaded on demand
subagents/ ← child agents
schedules/ ← cron-triggered prompts
connections/ ← MCP and OpenAPI services
sandbox/ ← isolated shell + network policy
evals/ ← scored checks
There is no registration code: agent/tools/get_weather.ts is the tool get_weather, and the filename is the name the model calls. That filesystem-first design has real consequences — load-bearing filenames, subagents that inherit nothing from their parent, approval gates on dangerous tools — and the deep dive on defining an Eve agent covers them properly.
What matters for the choice is what the runtime adds around that folder:
- Durability. A session can run for days. The agent can pause on an approval gate, wait for a human, and resume — no server of yours holding the state.
- Its own triggers. Schedules fire it on a cron; channels connect it to Slack; nothing about it requires a user request to exist first.
- Its own sandbox. It can run model-authored code in an isolated shell with a network egress policy you set.
- Its own tests. Evals assert on behavior —
t.calledTool("lookup_order")catches the confident invented answer — and run witheve evalbefore deploy.
None of that fits inside a request-response function, which is precisely why Eve is not a library. You deploy an Eve agent the way you deploy an app, because operationally it is one.
The boundary: request-scoped vs durable
Put side by side, the decision reads like this:
| AI SDK | Eve | |
|---|---|---|
| Shape | Library in your code | Framework + runtime, its own deploy |
| Lifetime | One request | Sessions up to days |
| Triggered by | Your code calling it | Schedules, channels, API — or nothing yet |
| State | The messages you pass in | Held by the runtime across pauses |
| Human approval | You build the pause | always() / once() gates built in |
| UI streaming | First-class (useChat) | Not the point |
| Testing | Your test framework | evals/ with behavioral asserts |
Concrete cases, sorted:
AI SDK: a support chat inside your product; "summarize this document" on a button; an agent step inside an existing background job; anything where the user is present and the answer streams back to a screen you own.
Eve: an agent that watches failed payments every morning and posts to Slack; a triage agent colleagues talk to in a channel; long-running research that pauses for approval before spending money; anything that should keep existing between interactions.
The tell in practice: if you find yourself building session persistence, cron wake-ups, or an approval queue around an AI SDK loop, you are re-implementing Eve's runtime — move up. If your Eve agent only ever runs when a user of your app clicks something and answers within the request, it is carrying a deploy it doesn't need — move down.
Using both is the normal endgame
The two compose more than they compete, and mature setups tend to hold both:
- The app uses the AI SDK; the operation uses Eve. Your product's chat feature is an AI SDK loop in a route handler. The agent that watches your error tracker overnight is an Eve deploy. Same company, different lifecycles, correctly different tools.
- Shared tool surfaces via MCP. Both sides can consume Model Context Protocol servers — Eve mounts them under
agent/connections/, the AI SDK connects as a client — so an internal MCP server makes your systems callable from every agent you run, whichever runtime hosts it. - Eve calling your app. An Eve agent's tools are TypeScript; nothing stops one from calling the same APIs your product exposes, with an approval gate on the writes.
What does not compose well is trying to make one of them be the other — an AI SDK loop wearing a hand-rolled scheduler, or an Eve agent used as a synchronous chat backend.
Where to start
For the AI SDK: npm install ai zod, pick a provider, and the loop above is a working agent — Vercel's own guide builds it up step by step.
For Eve: Node 24+, then npx eve@latest init my-agent gives you the folder and a local terminal UI. If you would rather see a complete agent before committing — tools with schemas, a subagent, the sandbox policy, evals — the free Eve agent generator produces the whole folder as a downloadable .zip, no account needed.
And if the agent is one piece of a larger product you are still designing, that design is the part worth doing first: Nodlume's workspace sketches the routes, data model and permissions the agent will work against, and its sibling generators cover the OpenAI Agents SDK, Claude Agent SDK, LangChain Deep Agents and Google ADK when the runtime question lands somewhere other than Vercel.
Target-specific scaffolding
Continue this learning path
Permissions, manifests, capabilities, agent projects and MCP servers for browser extensions, desktop, mobile, and backend agents.
Design your application
Design Web, Desktop, Mobile, Terminal, or Extension projects with a target-aware canvas and exporter.
Open projects