# Vercel AI SDK

The Vercel AI SDK runs model calls and tool loops in your TypeScript application.
Its OpenAI-compatible provider sends each request to the exchange through Chat Completions.

## Print the setup with the Liquid CLI

The [Liquid CLI](https://inference.ai.exchange/docs/cli.md) prints the setup for the Vercel AI SDK with your model filled in. To run your own program with the exchange in its environment, use `liquid exec`. It sets `OPENAI_BASE_URL`, `ANTHROPIC_BASE_URL` and the keys for that process only.

```bash
curl -fsSL https://inference.ai.exchange/cli/install.sh | bash
liquid login
liquid connect vercel-ai
liquid exec -- node app.mjs
```

To set up the SDK yourself, follow the steps below.

## Before you start

- Use Node 22 or later. The SDK does not accept an older release.
- Use a workspace with a balance and a key with the `spend` scope. See [API keys](https://inference.ai.exchange/docs/keys.md).
- Export the key in the shell that starts your application:

  ```bash
  export LIQUID_API_KEY=sk-liquid-...
  ```

## 1. Install the SDK

```bash
# Node 22 or later
npm install ai @ai-sdk/openai-compatible
```

See the [official provider guide](https://ai-sdk.dev/providers/openai-compatible-providers).

## 2. Add the exchange as a provider

Save this file as `liquid.ts`.

```typescript
import { createOpenAICompatible } from '@ai-sdk/openai-compatible'

const liquid = createOpenAICompatible({
  name: 'liquid',
  baseURL: 'https://router.inference.ai.exchange/v1',
  apiKey: process.env.LIQUID_API_KEY,
  headers: { 'x-liquid-cap-usd': '1.00' },
})

export const model = liquid('liquid.auto')
```

The base URL ends in `/v1`, because the provider adds `/chat/completions` to it.
Choose a model, router model, or preset from `GET /v1/models`. See [Market data](https://inference.ai.exchange/docs/market.md).

The `x-liquid-cap-usd` header sets a $1.00 cap for each request.

## 3. Send a request

```typescript
import { generateText } from 'ai'

import { model } from './liquid.ts'

const { text } = await generateText({ model, prompt: 'Say hello.' })
console.log(text)
```

## Purchasing rules

Put the `exchange` object in `providerOptions`, below the name of the provider.
The provider copies the object into the request body.
See [Purchasing rules](https://inference.ai.exchange/docs/rules.md) for the fields.

```typescript
const { text } = await generateText({
  model,
  prompt: 'Say hello.',
  providerOptions: { liquid: { exchange: { cap_usd: 0.05 } } },
})
```

The key `liquid` is the `name` that `createOpenAICompatible` received. A different key has no effect.

A cap in the body replaces the cap header. To change only the header for one call, set `headers` on that call:

```typescript
const { text } = await generateText({
  model,
  prompt: 'Say hello.',
  headers: { 'x-liquid-cap-usd': '0.05' },
})
```

If no offer fits the cap, the exchange refuses the request. It does not reduce the output limit.

To limit the total spend, use a separate key with a spend limit. The exchange refuses more requests after that limit.

## Local tools

A tool made with `tool()` runs in your application.
The exchange sends its definition to the provider and returns the model's tool calls.
The SDK runs each function and sends the result in the next request.

```typescript
import { readFileSync } from 'node:fs'

import { generateText, isStepCount, jsonSchema, tool } from 'ai'

import { model } from './liquid.ts'

const { text } = await generateText({
  model,
  prompt: 'Summarize notes.txt.',
  tools: {
    read_notes: tool({
      description: 'Read notes.txt from the current directory.',
      inputSchema: jsonSchema({ type: 'object', properties: {} }),
      execute: async () => readFileSync('notes.txt', 'utf8'),
    }),
  },
  stopWhen: isStepCount(6),
})
```

Without `stopWhen`, the SDK stops after one request and does not send the tool result.
`isStepCount(6)` permits six requests. Each request is a separate job with its own cap.

See the [official tool guide](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling) for schemas made with Zod.

## Stream a response

`streamText` uses the same model:

```typescript
import { streamText } from 'ai'

import { model } from './liquid.ts'

const result = streamText({ model, prompt: 'Say hello.' })
for await (const part of result.textStream) {
  process.stdout.write(part)
}
```

To get token counts from a stream, add `includeUsage: true` to the options of `createOpenAICompatible`.

## Read the job and its cap

The exchange returns the `x-liquid-job-id` and `x-liquid-cap-usd` headers before any token.
`x-liquid-cap-usd` is the maximum charge for the job.

```typescript
const result = await generateText({ model, prompt: 'Say hello.' })
const headers = result.response.headers
console.log(headers?.['x-liquid-job-id'], headers?.['x-liquid-cap-usd'])
```

With `streamText`, use `(await result.response).headers`.

## Verify the connection

Check the receipts on the **Credits** page. Requests show **Vercel AI SDK** as the client.
Use the receipt for the settled charge. The SDK's token usage does not state the exchange's charge.

## Troubleshooting

| Symptom                             | Cause and action                                                        |
| ----------------------------------- | ----------------------------------------------------------------------- |
| `401`                               | Confirm that `LIQUID_API_KEY` is set and the key has the `spend` scope. |
| `model_not_found`                   | Choose a name from `GET /v1/models`.                                    |
| The request exceeds the cap         | Reduce `maxOutputTokens` or increase the cap.                           |
| The purchasing rules have no effect | Use the provider `name` as the key in `providerOptions`.                |
| The model calls a tool and stops    | Add `stopWhen`, so that the SDK sends the tool result.                  |
| The request has insufficient funds  | Add funds to the workspace on the **Credits** page.                     |

## Next steps

- [Purchasing rules](https://inference.ai.exchange/docs/rules.md): caps, models, strategy, and service limits.
- [API keys](https://inference.ai.exchange/docs/keys.md): total spend limits for each application.
- [OpenAI SDK](https://inference.ai.exchange/docs/connect-openai-sdk.md): call the endpoints directly.
