# Vercel AI SDK

> Give a Vercel AI SDK agent your messaging channels, and let it answer incoming messages, in about ten minutes.

Source: https://docs.vlayers.ai/developers/frameworks/ai-sdk

Kind: Tutorial

## What you'll build

An AI SDK agent that texts a test number with VoiceLayer's `message_send` tool, then answers a simulated incoming text from your own process. You use `@voicelayer/agents/ai-sdk`, which loads the VoiceLayer [channel tools](https://docs.vlayers.ai/developers/mcp) as AI SDK tools over MCP.

## Prerequisites

- Node.js 22 or later, and TypeScript 5.2 or later if you compile your own (the examples run with `tsx`). The examples are ES modules with top-level `await`, and use `await using`, which closes a connection when the file ends (TypeScript 5.2 or later with `esnext.disposable` in `lib`; or close it yourself with `await tools[Symbol.asyncDispose]()`).
- A test key in `VOICELAYER_API_KEY` (`vl_test_…`): see [Authentication and API keys](https://docs.vlayers.ai/get-started/authentication). With a test key every send goes to a simulated carrier and costs nothing.
- A model provider for the AI SDK. The quickstart uses the AI Gateway model `openai/gpt-4.1-mini`, so set `AI_GATEWAY_API_KEY`.
- No phone number needed: with a test key, your workspace's free [test sender](https://docs.vlayers.ai/developers/test-mode#your-free-test-sender) stands in for one.

## Install

```bash
npm install @voicelayer/agents ai@7 @ai-sdk/mcp@2
```

Set the keys once. VoiceLayer's helpers read `VOICELAYER_API_KEY` themselves, so no example passes a key:

```bash
export VOICELAYER_API_KEY=vl_test_...
export AI_GATEWAY_API_KEY=...
npm pkg set type=module
```

## Give your agent VoiceLayer's tools

Save this as `agent.ts`.

```ts title="agent.ts"
import { ToolLoopAgent } from 'ai';
import { voicelayerTools } from '@voicelayer/agents/ai-sdk';

await using tools = await voicelayerTools();
const agent = new ToolLoopAgent({ model: 'openai/gpt-4.1-mini', instructions: 'You answer customers in one short sentence.', tools });

const { text } = await agent.generate({ prompt: 'Text "Hello from VoiceLayer" to +15550101 over sms.' });
console.log(text);
```

- `voicelayerTools()` connects to VoiceLayer over MCP and returns the tools as AI SDK tools. `await using` closes the connection when the file ends.
- `agent.generate()` asks the agent to text `+15550101`, a reserved test number. The agent calls `message_send`.

Run it:

```bash
npx --yes tsx agent.ts
```

The agent texts the test number and prints its answer.

## Answer incoming messages

Direct mode: your process answers the conversations VoiceLayer hands to code. Save this as `serve.ts`.

```ts title="serve.ts"
import { ToolLoopAgent } from 'ai';
import { serveDirect } from '@voicelayer/agents/ai-sdk';

const agent = new ToolLoopAgent({ model: 'openai/gpt-4.1-mini', instructions: 'You answer customers in one short sentence.' });
await serveDirect(agent);
```

`serveDirect(agent)` answers incoming messages with the agent: each message in a conversation your code controls becomes one generation, and the reply is sent back in that conversation. It keeps running until you stop the process.

```bash
npx --yes tsx serve.ts
```

```text
voicelayer: answering incoming messages (Ctrl+C to stop)
```

## Test it without a person

With the server from the last step running, open a second terminal and simulate a person texting you. Save this as `simulate.ts`.

```ts title="simulate.ts"
import { simulateInbound } from '@voicelayer/agents';

const { conversationId } = await simulateInbound({ text: 'What are your opening hours?' });
console.log(`Simulated a text from +15550101 in conversation ${conversationId}`);
```

```bash
npx --yes tsx simulate.ts
```

The first terminal prints `voicelayer: replied in conversation …`. Open **Conversations** in the dashboard and turn on test conversations to see the text and the reply. Both went to the simulated carrier.

Direct mode answers conversations your code controls (`api`). A new workspace's free test sender is yours by default; if the number you use has an agent that answers texts, [hand the conversation to your code](https://docs.vlayers.ai/developers/handoff) first.

To answer real people, swap the test key for a live key. Nothing else changes.

## Handle errors

A missing key stops the program at start with a message that names `VOICELAYER_API_KEY`. A wrong key, or anything else the API refuses, comes back as an error with a stable code:

| Error | Status | How to fix |
|---|---|---|
| [`unauthorized`](https://docs.vlayers.ai/errors/unauthorized) | 401 | Send `Authorization: Bearer <key>` with a secret key from the dashboard (Developers → API keys). Test keys start with `vl_test_`. |
| [`insufficient_scope`](https://docs.vlayers.ai/errors/insufficient_scope) | 403 | Use a key with the scope named in `details.required`, or one whose restriction covers this channel or Binding. |
| [`test_address_required`](https://docs.vlayers.ai/errors/test_address_required) | 422 | Use a reserved test address, or a live key to reach a real person. |
| [`test_mode_only`](https://docs.vlayers.ai/errors/test_mode_only) | 403 | Use a test key (`vl_test_…`) from the dashboard. |
| [`test_limit_reached`](https://docs.vlayers.ai/errors/test_limit_reached) | 429 | Try again after midnight UTC, or ask for a higher test limit. |

If the first terminal never prints a reply, the conversation is answered by your workspace's agent, not by your code. See [Hand off a conversation](https://docs.vlayers.ai/developers/handoff).

## Next steps

- [The MCP tools](https://docs.vlayers.ai/developers/mcp): what each tool does and which scope it needs.
- [Test mode](https://docs.vlayers.ai/developers/test-mode): more ways to simulate people.
- [LangChain and LangGraph](https://docs.vlayers.ai/developers/frameworks/langchain): the same setup with LangGraph.
