TypeScriptLow abstraction — you write the loop

Vercel AI SDK

A provider-agnostic TypeScript layer for text generation, streaming, tool calling, and structured output, with React/Next.js hooks for streaming UIs.

Architecture

  • AI SDK Core: generateText, streamText, generateObject/streamObject over a unified LanguageModel interface; providers are packages (@ai-sdk/anthropic, @ai-sdk/openai, …).
  • Tools: tool({ description, inputSchema: z.object(...), execute }); the loop runs client-side in your process with stopWhen/maxSteps controlling iterations.
  • Structured output: a Zod schema drives either native JSON mode or tool-based extraction per provider.
  • AI SDK UI: useChat/useCompletion hooks consume a streamed UI message protocol from a route handler; tool calls and results stream as typed parts.
  • Agent class (recent versions) packages model + tools + stop conditions for reuse; there is no persistence or graph runtime.

Best use cases

  • Next.js / React products that need streaming chat with tool calls rendered as UI.
  • Full-stack TypeScript teams that want one API across providers.
  • Edge/serverless deployments where a small, tree-shakeable dependency matters.

Weaknesses

  • Provider feature parity lags: newer provider options arrive via providerOptions escape hatches with weaker typing.
  • Major-version churn (v3 → v4 → v5) renamed core concepts (parametersinputSchema, maxStepsstopWhen, message formats); upgrades are not free.
  • Serverless execution limits make long tool loops awkward; there is no checkpointing or resumption, so durable agents need an external workflow engine.
  • The UI message protocol is Vercel's; consuming streams from non-React clients requires understanding the wire format.
  • Multi-agent orchestration is left to you — fine, but do not expect supervisor or handoff primitives.

When NOT to use it

  • Python backends — the TypeScript-only design is a hard constraint.
  • Long-running, resumable workflows with approvals across sessions.
  • You need heavy retrieval tooling; pair it with your own search or a dedicated RAG library.

Code example

Illustrative — APIs change between versions.

1import { generateText, tool, stepCountIs } from 'ai'
2import { anthropic } from '@ai-sdk/anthropic'
3import { z } from 'zod'
4
5const result = await generateText({
6 model: anthropic('claude-sonnet-4-5'), // model id is version-sensitive
7 system: 'You are a support agent. Use tools; never guess order status.',
8 prompt: 'Where is order A-123?',
9 tools: {
10 getOrder: tool({
11 description: 'Look up an order by id',
12 inputSchema: z.object({ orderId: z.string().regex(/^[A-Z]-\d+$/) }), // v5: inputSchema (v4: parameters)
13 execute: async ({ orderId }) => db.orders.find(orderId),
14 }),
15 },
16 stopWhen: stepCountIs(5), // iteration budget for the tool loop
17})
18
19console.log(result.text)
20for (const step of result.steps) {
21 console.log(step.toolCalls.map((c) => c.toolName), step.usage.totalTokens)
22}

Alternatives

Related lessons